Python File Handling

최병훈·2024년 9월 20일
post-thumbnail

File Handling

  • File은 Disk에 존재하고 운영체제가 관리하는 자원
  • File 입출력을 할 때는 스레드 프로그래밍을 이용하는 것이 좋고 버퍼링을 고민해봐야 합니다.
  • python 이 생성한 자원이 아니므로 자원의 존재 여부는 python이 알 수 없으므로 예외처리를 해주는 것이 좋습니다.

1. 파일 처리 과정

  • 파일을 열기
  • 파일에 읽기/쓰기
  • 파일 닫기

2. open 함수

  • 파일을 열어주는 함수
  • open(파일 경로, 모드) - 열기와 쓰기 결정, 인코딩 방식
  • 기록을 할 때는 write나 writelines(\n을 이용) 등을 이용해서 기록
  • 읽을 때는 read나 readline 또는 readlines 함수를 이용해서 읽기
  • 모드
    • r(read)
    • w(write) : 파일이 없으면 만들고 있으면 처음부터 기록
    • x : 배타적 생성 모드 - 파일이 존재하면 IOError 예외 발생
    • a : 맨 뒤에 추가
    • b(바이너리) : 파일의 내용을 바이트 단위로 읽어내는 것, 텍스트 파일이 아닌 경우에 주로 사용
    • t(텍스트모드)
    • +(읽기 쓰기 용)
  • w 모드 사용 : 파일을 열어서(없으면 생성) 내용을 작성
    try:
        # 파일 기록 모드(w)로 열기
        file = open("./test.txt", "w")
        file.write("안녕하세요")
        file.writelines(반갑습니다. \n여러 줄 작성 가능)
    except Exception as e:
        print("파일 쓰기 중 예외 발생:", e)
    finally:
        file.close()
  • r 모드 사용 : 파일 읽는 예시
    • 용량이 큰 경우 파일을 한번에 다 읽는 것은 위험
      try:
          # 기본적인 읽기는 이터레이터 형식 - 한 번 읽으면 다시 못 읽습니다.
          # 다시 읽고자 하는 경우는 open 부터 다시 해야 합니다.
          file = open("./test.txt", "r")
          content = file.read() # 한번에 다 읽기
          print(content)
      except Exception as e:
          print("파일 쓰기 중 예외 발생:", e)
      finally:
          file.close()
    • 줄 단위 읽기
      try:
          file = open("./test.txt", "r")
          # 줄 단위 읽기
          for line in file:
              print(line)
      except Exception as e:
          print("파일 쓰기 중 예외 발생:", e)
      finally:
          file.close()

3. with 구문

  • 파일은 열면 반드시 닫아 주어야 합니다.( close() 이용)
    • 닫아 주지 않으면 운영체제는 사용 중인 것으로 판단해서 다른 프로그램에서 이 파일을 읽기 모드로만 사용하도록 합니다.
  • with open() as 임시변수
    • 이 문법을 이용해서 파일을 열면 with 블럭이 끝날 때, 예외 발생 여부에 상관없이 파일을 닫아 줍니다.
     # with 블럭을 사용하면 with 안에서 개방한 파일을 닫지 않아도 블럭이 끝나면 자동으로 닫아줍니다.
      with open("./test.txt", "r") as file:
          # 줄 단위 읽기
          for line in file:
              print(line)

4. 데이터를 표현하기 위한 텍스트 파일

  • fwf
    • 일정한 간격을 가지고 문자열을 나열해서 데이터를 표현
     이름	  나이	  주소
      A	      34	  서울시 양천구 목동
      B	      27	  주소 불명
  • tsv
    • 탭으로 구분한 문자열을 이용해서 데이터를 표현
  • csv (Comma Separated Values)
    • 콤마를 이용해서 구분한 문자열을 이용해서 데이터를 표현
    • Open API 에서 변하지 않는 고정된 데이터를 제공할 때 주로 이용
    • 변하는 데이터의 경우는 예전에는 XML, 최근에는 JSON을 주로 이용

5. csv 읽기

  • 텍스트 파일 읽기를 이용한 후 split 같은 메서드를 이용해서 사용
    • split은 하나의 문자열을 매개변수 단위로 쪼개서 list로 리턴해주는 메서드
      # 한글이 포함된 경우는 encoding을 확인해 볼 필요가 있음
      with open("./data.csv", "r", encoding="utf-8") as file:
          datas = file.readline()
          print(datas)
          print(datas.split(sep=','))
          sample = file.readlines()
          print(sample)
  • 파이썬의 내장 모듈인 csv 모듈 활용
  • 외부 라이브러리로 제공되는 csv 읽는 메서드 활용
    • ex. pandas
    • 여러 옵션을 활용할 수 있음 - 복잡한 파일에 적합

6. 바이너리 파일

  • 바이트 단위로 읽고 쓰는 파일

  • 문자열을 직접 기록하지 않고 byte 배열로 변환해서 기록

    • 문자열을 byte 배열로 변환할 때는 encode 메서드 이용하고 반대로 byte 배열을 문자열로 변환할 때는 decode 메서드 이용
    • 이 기종 시스템 간에 문자열을 주고 받을 때는 문자열을 직접 주고 받지 않고 바이트 배열을 이용하는 경우도 있습니다.
    • 요즘은 채팅이 아니라면 이런 방식 보다는 xml 이나 json을 주고 받으라고 합니다.
  • 바이너리 파일을 읽고 쓸 때는 모드에 b를 추가하면 됩니다.

    • ajax로 서버의 데이터를 읽어올 때, 바로 출력하면 이 형태로 보일 수 있습니다.
  • 문자열을 byte 배열로 encode 하여 bin 파일에 저장

    with open("./test.bin", "wb") as f:
       # 문자열을 byte 배열(bytes)로 변환해서 기록
       f.write("안녕하세요".encode())
  • bin 파일에서 byte 배열을 읽고 문자열로 decode 하여 출력

    with open("./test.bin","rb") as f:
      byteArray = f.read()
      # 웹에서 ajax로 데이터 불러왔을 때 바로 출력하면 이 형태로 보입니다.
      print(byteArray)
      # byte 배열을 문자열로 변환해서 출력
      print(byteArray.decode())
  • encoding

    • 데이터를 메모리에 저장되는 형태로 변경하는 작업
    • 한글 encoding 들
      • euc-kr : 초창기 한글
      • cp949, ms949 : 윈도우 한글
      • utf8 : 현재 사용
      • utf8mb4 : 이모티콘
  • decoding

    • 메모리에 저장된 현태를 사람이 볼 수 있는 형태로 변경하는 것

7. Serializable

  • 인스턴스 단위로 파일에 저장하는 것

  • 응용 프로그램을 만들 때 사용하는 방법으로 파일이 존재한다고 하더라도 원본 클래스가 없으면 해석이 불가능

  • 파이썬에서는 pickle 모듈이나 DBM 관련 모듈을 이용해서 작업

  • 파일에 내용을 기록

    • pickle.dump(객체, 파일객체)
  • 파일에서 내용을 읽어오기

    • pickle.load(파일객체)
    • pickle.loads(파일객체)
  • pickle 모듈을 활용하여 인스턴스 1개를 파일에 저장 및 불러오기

    import pickle
    
    class VO:
        def __init__(self, num:int=0, name:str="") -> None:
            self.__num = num
            self.__name = name
        
        def setNum(self, num):
            self.__num = num
        def setName(self, name):
            self.__name = name
        
        def getNum(self):
            return self.__num
        def getName(self):
            return self.__name
        
        # 인스턴스를 출력하기 위해서, 인스턴스를 참조하는 데이터를, 출력하는 함수에 대입했을 때 호출되는 메서드
        def __str__(self) -> str:
            return f"번호:{self.__num} 이름:{self.__name}"
        
    
    data1 = VO(1, "아담")
    # 객체를 파일에 직접 저장 : Serializable
    with open('./test.txt', 'wb') as f:
        pickle.dump(data1, f)
    
    with open('./test.txt', 'rb') as f:
        data2 = pickle.load(f)
        print(data2)
  • pickle 모듈을 활용하여 여러 개의 인스턴스를 파일에 저장 및 불러오기

    import pickle
    
    class VO:
        def __init__(self, num:int=0, name:str="") -> None:
            self.__num = num
            self.__name = name
        
        def setNum(self, num):
            self.__num = num
        def setName(self, name):
            self.__name = name
        
        def getNum(self):
            return self.__num
        def getName(self):
            return self.__name
        
        # 인스턴스를 출력하기 위해서, 인스턴스를 참조하는 데이터를, 출력하는 함수에 대입했을 때 호출되는 메서드
        def __str__(self) -> str:
            return f"번호:{self.__num} 이름:{self.__name}"
        
    
    data1 = VO(1, "아담")
    data2 = VO(2, "이브")
    # 여러 개의 객체를 저장할 때, list로 묶어서 저장
    li = [data1, data2]
    
    with open('./test.txt', 'wb') as f:
        pickle.dump(li, f)
    
    with open('./test.txt', 'rb') as f:
        datas = pickle.load(f)
        for data in datas:
            print(data)

8. 파일 압축

  • 압축을 하는 이유는 여러 개의 파일을 하나로 만들어서 사용하거나 크기를 줄이기 위해서 사용

  • 클라우드에서 데이터를 백업하는 방식은 데이터베이스, 파일, 압축 파일 3종류가 있습니다.

    • 데이터베이스가 사용하기는 가장 편리하지만 오버헤드가 가장 큼
    • 파일은 데이터베이스보다는 오버헤드가 적고 대신 가용성은 떨어집니다.
    • 파일을 압축해서 저장하면 가장 사이즈가 작아지지만 사용을 할 때 압축을 해제해서 사용해야 하기 때문에 가장 가용성이 떨어집니다.
  • 오래되고 당장 사용하지 않을 것 같은 파일은 압축해서 보관하는 것이 좋습니다.

  • 파이썬은 기본적으로 zip 과 tar 압축 모듈을 제공

    • zip은 zipfile 이라는 모듈의 ZipFile 함수를 이용하서 객체를 생성하고 wirte 함수로 압축을 합니다.

      • 3개의 파일 압축 : data.csv, test.txt, test.bin
        import zipfile
        
        with zipfile.ZipFile("test.zip", "w") as myzip:
            # 압축할 파일 경로
            filelist = ["data.csv", "test.txt", "test.bin"]
            for file in filelist:
                myzip.write(file)

      • 파일 삭제 후 다시 압축 해제

      • 압축 해제는 extractall 이라는 함수를 이용

        # 압축 해제
        import zipfile
        
        zipfile.ZipFile("./test.zip").extractall()

    • 리눅스의 압축 표준인 tar는 tarfile 이라는 모듈의 open 함수를 이용해서 객체를 만들고 add를 이용해서 압축을 수행하고 extractall 함수를 이용해서 압축을 해제

0개의 댓글