1. 파일
■ 파일(file)은 보조 기억장치에서 문서, 소리, 그림, 동영상같은 자료를 모아놓은 것을 말한다.
■ 파일 안에는 바이트들이 순차적으로 저장되어 있고, 맨 끝에는 EOF(end-of-file) 마커가 있다.
■ 모든 파일은 위의 예시처럼 입출력 동작이 발생하는 위치를 나타내는 파일 포인터를 가지고 있다.
■ 파일을 열면, 파일 포인터는 파일의 첫 번째 바이트를 가리킨다. 그리고 파일의 내용을 읽거나 쓰면, 파일 포인터는 자동으로 업데이트된다.
2. 파일 열고 닫기
2.1 open()과 close()
■ 파일을 사용하려면 먼저 open( ) 함수로 파일을 열어야 한다.
■ open( ) 함수는 파일 이름과 파일 모드를 받아서 파일 객체를 생성한 후에 파일 객체를 반환한다.
■ 파일이 열리면 해당 파일에 데이터를 읽거나 쓸 수 있다.
■ 파일과 관련된 작업이 모두 끝나면 파일을 닫아야 한다. 이는 파일 객체가 가지고 있는 close()를 호출하면 된다. 어떤 경우라도 파일 연결은 파일객체.close() 명령으로 종료할 수 있다.
■ 파일을 열고 닫기 위해 사용하는 open()과 close()의 사용법은 다음과 같다.
파일객체 = open(파일명, 파일 모드)
...,
...,
파일객체.close()
f = open('input.txt', 'r')
...,
...,
f.close()
■ open() 함수의 첫 번째 파라미터는 파일의 이름이다. 위의 예시에서 open() 함수는 파일명이 'input'인 텍스트 파일을 열고, 파일과 연관된 객체를 생성한 다음, 파일 객체를 반환한다.
■ 파일에서 데이터를 읽거나 쓰려면 반드시 파일 객체가 필요하다. 만약, open() 함수가 파일을 여는데 실패하면 None 객체가 반환된다.
■ open() 함수의 두 번째 파라미터는 파일을 여는 모드. 파일 모드이다.
■ 파일 모드는 파일과 관련된 동작 방식을 지정하는 문자열이다. 위의 예시처럼 'r'이면 읽기 모드로, 파일 읽기 작업을 위하여 파일을 여는 것이다.
■ close() 함수는 파일을 닫기 위해 사용한다.
2.2 파일 모드
■ 기본적인 파일 모드로 'r', 'w', 'a'가 있다.
파일 모드 | 모드 이름 | 설명 |
r | 읽기 모드(read mode) | 파일의 처음부터 읽는다. 파일을 읽기만 할 때 사용한다. |
w | 쓰기 모드(write mode) | 파일에 내용을 쓸 때 사용한다. 파일의 처음부터 쓰며, 파일이 없으면 생성된다. 만약, 파일이 존재하면 기존의 내용은 지워진다. |
a | 추가 모드(append mode) | 파일의 마지막에 내용을 추가할 때 사용한다. 마찬가지로 파일이 없으면 생성된다. |
- 파일 모드는 이 외에 'r+'같은 읽기와 쓰기 혼합 모드, 파일을 이진(binary) 형식으로 실행하는 이진 모드 'b' 등이 있다.
■ 현재 작업 디렉토리가 아닌 특정 디렉토리에 존재하는 파일을 열어야 하는 경우가 있다.
■ 예를 들어 C: 드라이브의 어떤 폴더에 input.txt가 있다면, 다음과 같이 경로를 지정할 수 있다
f = open("C:\\...\\...\\input.txt", "r", encoding = "utf-8")
또는
f = open("C:/.../.../input.txt", "r", encoding = "utf-8")
■ \\은 \(백슬래시) 기호 자체를 의미한다. \은 이스케이프 문자 \n처럼 파이썬 의미를 가지는 기호이므로 \만 쓰면 특수 문자로 취급된다.
■ 예를 들어 input.txt가 n으로 시작하는 폴더에 저장되어 있을 때, 경로를 "C:\n..\input.txt"처럼 작성하면, \n 부분이 줄바꿈 기호로 해석된다. 이런 문제를 방지하기 위해 2개의 백슬래시를 붙여 표시하는 것이다.
■ \\외에 경로 구분자로 /(슬래시)를 사용할 수도 있다.
■ 만약, 파일이 현재 작업 디렉토리에 있다면 다음과 같이 경로를 붙이지 않아도 된다.
f = open("input.txt", "r", encoding = "utf-8")
2.3 파일에서 읽기
2.3.1 readline
■ 파일 크기가 매우 클 수 있기 때문에 일반적으로 파일의 모든 내용을 한 번에 읽기보다는 줄 단위로 끊어서 읽는다. 파일 전체를 한 번에 읽으려면 파일 객체가 가지고 있는 read() 메서드를, 한 줄을 읽으려면 readline() 메서드를 호출한다.
■ 1.의 파일 포인터 예시처럼 텍스트 파일을 열면 1개의 파일 포인터는 해당 파일의 첫 번째 행을 시작으로 맨 첫 부분을 가리킨다.
■ 이때, 매번 변수=파일객체.readline()의 명령이 실행되면, 현재 행은 변수에 설정되고, 파일 포인터는 현재 행의 끝에 도달할 때까지 진행된다. 이 진행 과정에서 텍스트를 읽어 반환하는 것이다.
■ 한 행을 다 반환하면, 파일 포인터는 다음 행으로 이동한다.
■ readline() 메서드는 파일의 모든 행을 읽은 후에 공백 문자열까지 포함하여 반환한다.
■ 예를 들어, input.txt 파일에 다음과 같이 2줄이 저장되어 있다고 하자.
애플
사과
f = open('input.txt', 'r')
line = f.readline()
print(line)
line = f.readline()
print(line)
line = f.readline()
print(line)
line = f.readline()
print(line)
```#결과#```
애플
사과
````````````
■ 첫 번째 readline() 호출은 "애플\n" 문자열을 반환한다. 두 번째 readline() 호출은 "사과\n" 문자열을 반환한다. 세 번째 readline() 호출은 더 이상 읽을 행(줄)이 없기 때문에 공백 문자열 ""이 반환된다.
f = open('input.txt', 'r')
line = f.readline()
while line != "" :
print(line)
line = f.readline()
f.close()
```#결과#```
애플
사과
````````````
■ 이 예를 실행하는 동안 파일 포인터의 위치는 다음과 같다.
■ 이 예에서 "애플" 다음에 빈 줄이 출력되는 이유는 line 변수 안에 줄바꿈 문자 "\n"이 저장되어 있기 때문이다.
■ 예시처럼 문자열의 오른쪽에 줄바꿈 문자를 삭제하려면 rstrip() 메서드를 사용하면 된다. strip()을 사용해도 된다.
- strip()은 문자열의 첫 부분과 끝부분에서 줄바꿈 문자같은 공백 문자를 제거한다.
- rstrip()은 끝부분(맨 오른쪽)에 위치한 공백 문자만 제거한다.
f = open('input.txt', 'r')
line = f.readline().strip()
while line != "" :
print(line)
line = f.readline().strip()
f.close()
```#결과#```
애플
사과
````````````
f = open('input.txt', 'r')
line = f.readline().rstrip()
while line != "" :
print(line)
line = f.readline().rstrip()
f.close()
```#결과#```
애플
사과
````````````
■ 만약, 파일 안에 문자가 아닌 숫자 데이터가 저장되어 있을 때, 문자열을 숫자로 변환하고 싶다면 int() 함수를 사용하여 데이터 타입을 정수로 만들거나, float() 함수를 사용하여 부동소수점으로 만들 수 있다.
line = f.readline().rstrip()
num1 = int(line)
또는
num2 = float(line)
■ 다음과 같이 while 문으로 무한 루프를 만들어서, 무한 루프 안에서 파일객체.readline()을 호출해 계속 한 행씩 읽어 들여 모든 줄을 출력할 수도 있다.
■ 더 이상 읽을 행이 없으면 공백 문자열이 반환되기 때문에, break 명령문을 사용하여 무한 루프에서 빠져 나와야 한다.
f = open('input.txt', 'r')
while True:
line = f.readline()
if line == "":
break
print(line)
f.close()
```#결과#```
애플
사과
````````````
■ 다른 방법은 다음과 같이 for 문을 사용하는 것이다. 파일은 문자열들이 저장되어 있는 시퀀스 객체로 볼 수 있다.
f = open('input.txt', 'r')
for line in f:
line = line.rstrip()
print(line)
f.close()
```#결과#```
애플
사과
````````````
2.3.2 readlines
■readlines 함수는 파일의 모든 줄을 읽어서 각각의 줄에 있는 것을 요소로 가지는 리스트를 반환한다.
f = open('input.txt', 'r')
lines = f.readlines()
lines
f.close()
```#결과#```
['애플\n', '사과']
````````````
f = open('input.txt', 'r')
lines = f.readlines()
for line in lines:
print(line)
f.close()
```#결과#```
애플
사과
````````````
f = open('input.txt', 'r')
lines = f.readlines()
for line in lines:
line = line.strip()
print(line)
f.close()
```#결과#```
애플
사과
````````````
2.3.3 read
■ read() 함수는 파일의 전체 내용을 문자열로 반환한다.
f = open('input.txt', 'r')
lines = f.read()
print(lines)
f.close()
```#결과#```
애플
사과
````````````
2.4 파일에 쓰기
2.4.1 write
■ 파일을 쓰기 모드인 "w" 모드로 열었다면, 해당 파일이 이미 존재한다면 원래 내용이 모두 사라지고, 해당 파일이 존재하지 않으면 새로운 파일이 생성된다.
■ "w" 모드로 열었을 때, write() 메서드를 사용하여 파일에 텍스트를 쓸 수 있다. 예를 들어 다음과 같이 문자열 "포테이토"를 파일에 쓸 수 있다.
f = open('new.txt', 'w')
f.write('포테이토\n')
- 파일에 쓸 때, 줄 바꿈을 원한다면 마지막 부분에 줄 바꿈 문자를 붙여줘야 한다.
■ 다음과 같이 포매팅을 이용하여 변수의 값을 문자열 안에 포함시킬 수 있다.
num = 5
f.write(f'포테이토 개수={num}\n')
f.write('포테이토 개수=%s\n' % num)
■ 유의해야 할 점은, write() 함수는 자동 줄 바꿈이 되지 않기 때문에 줄 바꿈 문자 \n을 직접 추가해야 한다는 점이다.
■ write() 함수를 여러 번 사용하여 각 줄에 입력할 내용을 각각 넣을 수도 있다. 단, 이러한 방식은 입력할 데이터가 많은 경우 비효율적이다.
■ 이런 경우, 다음과 같이 각 줄에 입력할 데이터를 요소로 가지는 리스트를 만든 다음, for 문을 반복해서 write()를 실행하게 할 수 있다.
list1 = ['포테이토', '감자','애플', '사과']
with open('input.txt', 'w') as f:
for item in list1:
f.write(f'{item}\n')
!type input.txt
```#결과#```
포테이토
감자
애플
사과
````````````
2.4.2 writelines
■ writelines() 함수는 readlines() 함수처럼 여러 줄을 한 번에 작업하는 메서드이다. 그러므로 writelines()는 for문이나 다른 조건문이 별도로 필요하지 않다.
■ 위와 같이 리스트를 이용할 경우, 리스트의 요소인 각 문자열에는 줄바꿈 기호 \n가 포함되어 있어야 한다.
list2 = ['포테이토\n', '감자\n','애플\n', '사과']
with open('input.txt', 'w') as f:
f.writelines(list2)
!type input.txt
```#결과#```
포테이토
감자
애플
사과
````````````
2.4.3 'r+' 모드와 seek() 함수
■ 'r+' 모드는 읽기와 쓰기가 모두 가능한 모드이다.
■ 'r+' 모드로 파일을 열 때, 현재 위치를 가리키는 파일 포인터를 제어하기 위해 주로 seek() 함수를 사용한다.
■ 파일을 읽을 때와 쓸 때, 모두 파일 포인터가 변하기 때문에 생각한 것과 다른 위치에서 작업이 실행될 수 있다.
■ 예를 들어, 'r+' 모드로 파일을 열었을 때, 파일 포인터는 맨 첫 부분에 배치된다. 그러므로 이 상태에서 write() 함수로 쓰기 작업을 실행하면, 기존 파일의 내용이 덮어쓰여진다.
■ 이런 문제를 피하기 위해 seek() 함수로 파일 포인터를 변경한 다음, 작업을 진행하는 것이다. seek() 함수는 파일 내 특정 위치로 파일 포인터를 이동시킨다.
with open ('input.txt', 'r+') as f:
lines = f.read() # 파일의 모든 내용 읽기
print(lines);print('--'*5)
f.write('\n')
f.write('dog and cat')
f.seek(0) # 파일 포인터를 파일 맨 첫 부분으로 이동
f.write('dog\n') # 파일 내용 덮어쓰기 # 파일 포인터 이동
f.write('cat') # 파일 내용 덮어쓰기 # 파일 포인터 이동
lines = f.read() # 현재 위치에서 파일 읽기
print(lines);print('--'*5)
f.seek(0) # 파일 포인터를 파일 맨 첫 부분으로 이동
lines = f.read()
print(lines);print('--'*5)
```#결과#```
포테이토
감자
애플
사과
----------
감자
애플
사과
dog and cat
----------
dog
cat
감자
애플
사과
dog and cat
----------
````````````
- 첫 번째 lines = f.read()에서 파일의 모든 내용을 읽어 온다. 즉, 파일 포인터는 맨 처음부터 파일 끝까지 이동하게 되며, 모든 내용을 읽어 온다. 그래서 첫 번째 출력 결과 lines 변수에 "포테이토\n감자\n애플\n사과"라는 문자열이 저장된 것을 볼 수 있다.
- read() 함수를 사용했기 때문에 현재 파일 포인터의 위치는 파일의 끝에 위치한다. 그러므로 이어서 실행되는 f.write('\n'), f.write('dog and cat') 는 현재 파일 포인터 위치인 파일 끝에 "\n", "dog and cat"이라는 내용이 추가된다.
- 그다음, f.seek(0)을 통해 파일 포인터를 다시 맨 처음(0번 위치)으로 이동시킨다. seek() 함수에 전달된 숫자 0은 절댓값으로 파일의 위치를 의미한다.
- f.seek(0)을 통해 파일 포인터를 파일의 맨 처음으로 이동시킨 상태에서 f.write('dog\n')를 실행하면, 기존의 "포테이토\n" 부분이 "dog\n"으로 덮여 쓰여지기 시작한다.
- f.write('cat')을 실행하면, 현재 파일 포인터 위치는 'cat'의 바로 뒤를 가리키고 있게 된다.
- 이 상태에서 lines = f.read()로 현재 파일 포인터의 위치('cat'의 바로 뒤)부터 파일 끝까지의 내용을 읽게 된다. 그 결과가 바로 두 번째 출력 결과이다.
- "감자\n"라는 기존 문자열이 "cat"으로 덮여쓰여졌을 것처럼 보이지만, 두 번째 출력 결과를 보면 실제로는 그렇지 않은 것을 볼 수 있다. 이는 사람이 세는 글자 수와 다르게 컴퓨터는 바이트(byte) 단위로 읽기 때문이다.
- 영어나 공백은 자릿수 하나당 1 byte를 차지하며, 한글은 UTF-8 인코딩을 사용할 경우 글자당 3 byte를 사용한다.
- 즉, 기존 "포테이토\n"은 더 많은 바이트를 차지하고 있었기 때문에 "포테이토\n" 자리에 "dog\n"과 "cat" 문자열이 모두 들어갈 수 있어 "포테이토\n" 뒤의 "감자\n" 문자열은 덮이지 않고 남아 있게 된 것이다.
- 참고로 한글은 UTF-8 인코딩을 사용할 경우 글자당 3 byte, EUC-KR이나 CP949 인코딩을 사용할 경우 2 byte이다.
- 마지막 출력 결과는 f.seek(0)으로 파일 포인터를 맨 앞으로 옮긴 후, f.read()를 통해 전체 파일 내용을 읽었기 때문에, 새로 덮어쓴 "dog"와 "cat"부터 파일의 마지막 내용인 "dog and cat"까지의 문자열이 출력된다.
참고) 순차 접근(sequential access)과 임의 접근(random access)
■ 순차 접근 방법에 기반한 파일의 입출력 방법은 파일의 처음부터 순차적으로 접근하여 읽거나 기록한다.
■ 이런 방법의 단점은 한 번 읽은 데이터를 다시 읽으려면 현재 파일을 닫고 다시 열어야 한다는 점과 앞 부분을 건너뛰고 중간이나 마지막 부분으로 바로 접근할 수 없다는 점이다.
■ 반면, 임의 접근 방법은 파일 내 어느 위치에서든 읽기와 쓰기가 가능하다.
■ 모든 파일에는 파일 포인터(file pointer)가 존재한다. 새 파일을 생성하면 파일 포인터는 값이 0이 된다. 이는 파일의 시작 부분을 가리키는 것이다.
■ 새 파일이 아니라 이미 존재하는 기존 파일을 열 경우, 추가 모드에서는 파일의 끝을 가리키고, 다른 모드에서는 파일의 시작 부분을 가리킨다.
■ 읽기나 쓰기 작업이 수행될 때마다 파일 포인터의 위치는 갱신된다.
- 예를 들어, 읽기 모드로 파일을 열었을 때 10 바이트를 읽었다면, 파일 포인터의 값은 10
- 추가로 100 바이트를 읽었다면, 파일 포인터의 값은 110이 된다.
■ 순차 접근 방법으로 파일을 읽을 경우, 파일 포인터는 파일 시작 위치부터 시작해 파일의 끝으로 순차적으로 이동한다.
■ 파일 데이터를 모두 읽지 않고 원하는 특정 위치를 골라서 읽고 싶은 경우, seek() 함수를 이용하여 파일 포인터를 임의의 위치로 이동시킬 수 있다.
cf) 파일 포인터의 현재 위치는 tell() 함수로 알 수 있다.
2.4.4 현재 파일에 행(줄) 하나 추가하기
■ 추가 모드인 'a'는 파일의 끝에 새로운 행을 추가한다. write() 함수나 writeliness() 함수로 새로운 행을 추가하는 데 사용할 수 있다.
f = open('input.txt', 'a')
f.write(' and bird')
f.close()
!type input.txt
```#결과#```
dog
cat
감자
애플
사과
dog and cat and bird
````````````
2.5 파일 닫기
■ 파일 작업을 마쳤으면 파일을 닫아야 한다. close()는 열려 있는 파일 객체를 닫아 주는 역할을 한다.
■ 파이썬은 열려 있는 파일의 객체를 자동으로 닫아 주지만, 다음과 같이 close()를 사용해서 열려 있는 파일을 직접 닫아 주는 것이 좋다.
■ 쓰기 모드로 열었던 파일을 close()로 닫지 않는다면 write()로 쓴 데이터가 정상적으로 저장되지 않거나, 다시 사용하려면 오류가 발생하기 때문이다.
f = open('input.txt', 'w') # 파일 열기 # 쓰기 모드
f.write('감자\n')
f.close() # 파일 닫기
■ 위의 방법은 완전하지는 않다. open()과 close() 코드 중간에 오류가 발생하면 파일을 제대로 닫지 않고 코드가 종료될 수 있기 때문이다. 이런 문제를 방지하기 위해 다음과 같이 try-finally 블록을 사용한다.
try:
f = open('input.txt', 'w')
f.write('감자\n')
finally: # 예외가 발생하더라도 반드시 실행
f.close()
■ 이렇게 try-finally 구문을 사용한다면, try의 블록에는 예외가 발생할 가능성이 있는 작업들을 두고, finally 블록에는 예외가 발생하더라도 반드시 실행하니 finally에 f.close()를 두면 프로그램을 중지시키는 예외가 발생하더라도 파일을 정상적으로 닫을 수 있다.
■ 파일을 닫는 가장 좋은 방법은 with 명령문을 사용하는 것이다. with 문을 사용하면, with 블록이 종료될 때 파일이 자동으로 닫히기 때문이다. 즉, close()를 명시적으로 호출할 필요가 없다. close() 호출이 내부적으로 이루어지는 것이다.
with open('input.txt.', 'w') as f:
f.write('포테이토\n')
f.write('감자\n')
■ 읽기 모드도 쓰기 모드와 동일하게 with 문으로 실행할 수 있다.
with open('input.txt', 'r', encoding = 'utf-8') as f:
lines = f.read()
print(lines)
3. 텍스트 파일의 다양한 입출력 방법
3.1 단어로 분리하기
■ 텍스트 파일에 저장된 문장은 split() 함수를 사용해 공백 문자를 기준으로 단어로 나눠 리스트에 저장할 수 있다.
f = open('new.txt', 'r')
lines = f.read()
print(lines)
f.close()
```#결과#```
The! first word? in, business news.
````````````
with open('new.txt', 'r') as f:
for line in f:
line = line.strip()
word_list = line.split()
for word in word_list:
word = word.strip('.,!?')
print(word)
```#결과#```
The
first
word
in
business
news
````````````
- 단어에 붙어 있는 문장 부호들을 제거하고 싶으면 위와 같이 strip()류 함수의 인자에 제거할 문장 부호들을 지정하면 된다.
- 이 예에서 split()를 사용했기 때문에 분리자가 공백이다.
3.2 문자 단위로 읽기
■ read() 함수에 인자를 아무것도 넣지 않으면 파일에 있는 전체 내용을 읽게 된다. read() 함수에 인자로 숫자를 넣으면 원하는 개수만큼의 글자를 읽을 수도 있다.
■ 예를 들어 한 문자씩 읽고 싶으면 다음과 같이 read(1)을 호출하면 된다.
with open('new.txt', 'r') as f:
while True:
ch = f.read(1)
if ch == "": break
print(ch)
```#결과#```
T
h
e
!
f
i
...
````````````
4. 디렉토리
■ 디렉토리 작업은 os 모듈에서 제공하는 함수들을 사용할 수 있다.
■ 현재 파이썬 프로그램이 실행되는 디렉토리를 작업 디렉토리(CWD: Current Working Directory)라고 한다.
4.1 os.getcwd()
■ 작업 디렉토리를 얻으려면 os 모듈의 getcwd() 함수를 호출하면 된다.
import os
cwd_dir = os.getcwd()
4.2 os.chdir()
■ 처리해야 할 파일들이 다른 디렉토리에 저장되어 있다면 chdir() 함수를 통해 디렉토리를 바꿔주면 된다.
new_dir = os.chdir("C:/Users/USER/Desktop/")
■ 디렉토리가 변경된 것을 확인할 수 있다.
cwd_dir == new_dir
```#결과#```
False
````````````
4.3 os.listdir()
■ listdir() 함수는 지정한 디렉토리 안에 있는 모든 파일 및 디렉토리 이름이 들어있는 리스트를 반환한다.
os.listdir()
type(os.listdir())
```#결과#```
list
````````````
4.3.1 디렉토리의 파일 목록 조회
■ 파일만 처리하면 다음과 같이 isfile() 함수를 사용하면 된다. 해당 경로에 있는 파일이 정말 파일인지 확인할 때 사용한다. 정말 파일이면 True, 파일이 아니거나 존재하지 않으면 False를 반환한다.
if os.path.isfile('mod1.py'):
print('mod1.py')
```#결과#```
True
````````````
os.path.isfile('mod3.py')
```#결과#```
False
````````````
■ endswidth() 함수를 사용하면 파일의 확장자를 검사할 수 있다.
listdir = os.listdir()
for files in listdir: # files = 모든 파일 및 디렉토리 이름
if os.path.isfile(files): # 파일인 것만
if files.endswith('.py'): # 파일 중 확장자가 '.py'인 것만
print(files) # 해당 파일 이름 출력
```#결과#```
mod1.py
mod2.py
test_mypy.py
````````````
- 위의 코드는 확장자가 '.py'인 파일은 전부 찾아서 파일 이름을 출력하는 코드이다.
4.4 os.mkdir()
■ mkdir() 함수를 사용해 다음과 같이 원하는 경로에 새로운 디렉토리를 생성할 수 있다. 단, 디렉토리 이름이 해당 경로에 이미 존재하면 오류가 발생한다.
os.mkdir('/mkdir')
os.mkdir('/mkdir')
```#결과#``
FileExistsError: [WinError 183] 파일이 이미 있으므로 만들 수 없습니다: '/mkdir'
```````````
4.5 os.makedirs()
■ makedirs() 함수는 하위 디렉토리를 연속으로 생성할 때 사용한다.
■ 예를 들어, 다음 코드는 mkdir 디렉토리 안에 a라는 이름의 디렉토리를 생성하고, a 안에 b, b 안에 c를 생성하는 코드이다.
os.makedirs('mkdir/a/b/c')
4.6 os.rmdir()
■ rmdir() 함수는 삭제할 디렉토리를 지정하면, 해당 디렉토리를 삭제하는 함수이다. 단, 해당 디렉토리 안이 비어 있어야 삭제가 가능하다. 디렉토리 내에 다른 디렉토리나 파일이 존재하면 오류가 발생한다.
os.rmdir('mkdir/a/b') # 디렉토리 b 안에 디렉토리 c가 존재하고 있는 상태
```#결과#```
OSError: [WinError 145] 디렉터리가 비어 있지 않습니다: 'mkdir/a/b'
````````````
os.rmdir('mkdir/a/b/c') # 디렉토리 c 삭제
os.chdir('mkdir/a/b/c')
```#결과#```
FileNotFoundError: [WinError 2] 지정된 파일을 찾을 수 없습니다: 'mkdir/a/b/c'
````````````
4.7 os.removedirs()
■ os.makedirs() 함수와 정반대의 기능을 수행하는 함수이다. 지정된 경로의 가장 끝에 있는 디렉토리부터 시작하여, 상위 디렉토리들을 거슬러 올라가며 차례대로 삭제한다.
os.removedirs('mkdir/a/b') # 디렉토리 b부터 mkdir까지 삭제
4.8 os.remove()
■ removedirs() 함수가 디렉토리를 삭제하는 함수였다면, remove() 함수는 경로에 지정한 파일을 삭제하는 함수이다. 단, 파일이 열려 있으면 삭제할 수 없다.
os.remove('test.py') # 현재 디렉토리에 있는 test.py 파일 삭제
4.9 os.path.exists()
■ 경로에 지정한 파일이 존재하는지 확인하는 함수이다.
os.path.exists('mod1.py')
```#결과#```
True
````````````
■ os.path.isfile()은 경로에 지정한 파일이 정말 파일인지, os.path.exists()은 경로에 지정한 파일이 존재하는지 확인하여 True/False를 반환한다.
4.10 os.rename()
■ rename() 함수는 파일의 경로와 이름을 바꿔주는 함수이다.
os.rename('test_mypy.py', 'test.py') # 이름만 변경
listdir = os.listdir()
for files in listdir:
if os.path.isfile(files):
if files.endswith('.py'):
print(files)
```#결과#```
mod1.py
mod2.py
test.py
````````````
os.rename('test.py', 'C:\\Users\\Desktop\\test2.py') # 경로와 이름을 변경
5. 이진 파일
■ 파일(file)과 이진 파일(binary file)의 차이점은 파일에 기록되는 데이터의 형태가 다르다는 것이다.
■ 텍스트 파일은 모든 정보가 문자열로 파일에 저장된다. 예를 들어 숫자 123456을 저장하더라도 실제 파일에는 "123456"이라는 문자열이 기록된다. 즉, 텍스트 파일은 사람이 읽을 수 있는 문자로 기록된다.
■ 반면, 이진 파일은 사람이 읽을 수 없는 이진수 형태로 데이터가 기록된다.
■ 또한, 텍스트 파일은 아스키같은 인코딩을 사용하기 때문에 서로 다른 컴퓨터 환경에서도 파일을 열 수 있지만, 이진 파일은 인코딩 차이로 인해 인코딩 문제가 발생할 수 있다. 즉, 텍스트 파일에 비해 이식성이 떨어진다.
■ 이진 파일은 같은 내용을 저장하더라도 텍스트 파일보다 파일 크기가 작기 때문에 저장 공간을 적게 차지한다는 장점이 있다.
■ 이진 파일에서 데이터를 읽는 것도 open() 함수를 사용하여 파일을 열면 된다.
f = open('파일명', 'rb')
■ with 문을 이용하는 것도 가능하다.
with open('파일명', 'rb') as f:
...,
...,
...
■ 마찬가지로 파일 객체에 read() 함수를 사용하면 전체 내용을 읽어온다. 단, 이진 파일이라 단위가 바이트(byte)이므로, 예를 들어 read(1)이면 1 byte를 읽고, read(8)이면 8 byte를 읽는다.
byte1 = f.read(1)
byte8 = f.read(8)
■ 이진 파일에 바이트들을 저장하려면 다음과 같이 bytes() 함수를 이용하면 된다.
f = open('ff.bin', 'wb')
bytesArray = bytes([255, 128, 0, 1])
f.write(bytesArray)
bytesArray
```#결과#```
b'\xff\x80\x00\x01'
````````````
text_data = 'Let sleeping dog lie.'
f = open('aa.bin', 'wb')
text_encode = text_data.encode()
f.write(text_encode)
f.close()
text_encode
```#결과#```
b'Let sleeping dog lie.'
````````````
f = open('aa.bin', 'rb')
bdata = f.read()
bdata_decode = bdata.decode()
f.close()
text_encode
```#결과#```
'Let sleeping dog lie.'
````````````
6. 객체 출력
■ 2.에서 3.의 내용은 문자열 데이터를 텍스트 파일에 쓰고 읽는 방법에 대한 설명이다.
■ 파이썬에서 문자열이 아닌 딕셔너리, 리스트, 클래스와 같은 객체도 형식 그대로 유지하면서 파일로 저장하고 불러올 수 있다. 이때 사용하는 모듈이 pickle이다.
■ 딕셔너리, 리스트 등의 요소가 많을 경우, 데이터를 그대로 저장하면 용량이 매우 커질 수 있다. pickle을 사용하면 바이너리(binary) 형태로 저장되기 때문에 용량을 크게 줄일 수 있다.
6.1 pickle
■ 예를 들어, 다음과 같은 딕셔너리가 있다고 하자.
data = {}
data[1] = {'no':10, 'money':1000, 'quality':'high', 'shopping_list':['apple','바나나','grape']}
data['discount_rate'] = 0.5
print(data)
```#결과#```
{1: {'no': 10, 'money': 1000, 'quality': 'high', 'shopping_list': ['apple', '바나나', 'grape']}, 'discount_rate': 0.5}
````````````
■ pickle 모듈의 dump()와 load() 메서드를 사용하여 객체를 쓰고 읽을 수 있다.
■ 생성한 딕셔너리를 확장자가 '.p'인 피클 파일로 저장하는 방법은 다음과 같다.
# 딕셔너리 객체를 pickle 모듈로 압축
with open('data.p', 'wb') as f:
pickle.dump(data, f)
또는
f = open('data.p', 'wb')
pickle.dump(data, f)
f.close()
■ pickle.dump(data, f)는 data.p라는 파일에 딕셔너리 data를 저장한다는 의미이다. 이때 저장하는 데이터는 바이너리이므로 'wb' 형태의 쓰기 모드를 지정해야 한다.
■ 바이너리(이진) 파일인 피클 파일 'data.p'는 바이너리 데이터 형식으로 내용이 저장되어 있으므로, 파일 내용은 아래와 같이 사람이 읽기는 어렵다.
!type data.p
```#결과#```
�븏}�(K}�(�no봌
�money봎��quality뵆high뵆
shopping_list�]�(�apple뵆 諛붾굹�굹뵆grape봢u�
discount_rate봆?�u.
````````````
■ 피클 파일에 저장된 내용을 (복원해서) 불러오려면 load() 메서드를 사용하면 된다.
with open('data.p', 'rb') as f:
load_data = pickle.load(f)
print(load_data)
```#결과#```
{1: {'no': 10, 'money': 1000, 'quality': 'high', 'shopping_list': ['apple', '바나나', 'grape']}, 'discount_rate': 0.5}
````````````
■ 마찬가지로 불러올 피클 파일은 바이너리이므로 'rb' 형태의 읽기 모드를 지정해야 한다.
'파이썬' 카테고리의 다른 글
내장 함수, 정렬과 탐색, 람다식 (1) | 2024.09.07 |
---|---|
함수 (1) | 2024.09.06 |
제어문(control statement) (2) - 반복문 for, while (0) | 2024.09.02 |
제어문(control statement) (1) - 조건문 if (0) | 2024.08.28 |
자료형(Data Type) (4) - 세트(집합), 딕셔너리 (0) | 2024.08.24 |