지금까지는
input()으로 사용자에게 값을 입력받고,print()로 모니터에 결과를 출력했다.
하지만 프로그램에서는 파일을 통해 데이터를 입력받거나 결과를 파일에 저장하는 방법도 많이 사용한다.
파이썬에서는 open() 함수를 사용하여 파일을 열고 읽거나 쓸 수 있다.
파일 열기
↓
파일 읽기 / 쓰기
↓
파일 닫기
1. 파일 생성하기
2. 파일을 쓰기 모드로 열어 내용 쓰기
3. 파일을 읽는 여러 가지 방법
4. 파일에 새로운 내용 추가하기
5. with 문과 함께 사용하기
6. 파일 처리 시 주의사항
7. 핵심 정리
파이썬에서 파일을 다루기 위해서는 먼저
open()
함수를 사용한다.
예를 들어 다음 코드를 실행해 보자.
f = open("새파일.txt", "w")
f.close()
코드를 실행하면 현재 프로그램이 실행된 위치에
새파일.txt
파일이 생성된다.
open()의 기본 구조는 다음과 같다.
파일객체 = open("파일이름", "파일열기모드")
예를 들어
f = open("새파일.txt", "w")
에서
open()
│
├─ "새파일.txt" → 파일 이름
│
└─ "w" → 파일 열기 모드
이다.
그리고 open()이 반환한 파일 객체가 변수 f에 저장된다.
open("새파일.txt", "w")
↓
파일 객체
↓
f
이후 f를 이용해 파일을 읽거나 쓸 수 있다.
파일을 어떤 목적으로 사용할 것인지에 따라 모드를 지정한다.
| 모드 | 의미 | 설명 |
|---|---|---|
r | Read | 파일을 읽을 때 사용 |
w | Write | 파일에 내용을 쓸 때 사용 |
a | Append | 기존 내용 뒤에 새로운 내용을 추가할 때 사용 |
r - 읽기 모드f = open("test.txt", "r")
파일의 내용을 읽기 위한 모드이다.
test.txt
↓
Python 프로그램이 읽음
w - 쓰기 모드f = open("test.txt", "w")
파일에 내용을 작성하기 위한 모드이다.
w 모드로 열었는데 해당 파일이 이미 존재한다면
기존 내용
↓
모두 삭제
↓
새로운 내용 작성
이 된다.
예를 들어 test.txt에
Hello
Python
이 저장되어 있어도
f = open("test.txt", "w")
로 열면 기존 내용이 없어질 수 있다.
⭐
w모드는 기존 파일의 내용을 덮어쓴다.
파일이 존재하지 않는다면 새로운 파일을 생성한다.
a - 추가 모드f = open("test.txt", "a")
기존 파일의 내용을 유지하면서 마지막에 새로운 내용을 추가한다.
기존 내용
기존 내용
──────────
새로운 내용 ← 추가
⭐ 기존 내용을 유지하면서 추가하려면
a를 사용한다.
r, w, a 한눈에 보기r = Read
↓
읽기
w = Write
↓
쓰기
↓
기존 내용 삭제 주의
a = Append
↓
추가
↓
기존 내용 유지
파일 작업이 끝났다면 파일을 닫아 주는 것이 좋다.
f = open("새파일.txt", "w")
f.close()
close()는 열려 있는 파일 객체를 닫는다.
open()
↓
파일 열림
↓
작업
↓
close()
↓
파일 닫힘
프로그램이 종료될 때 파이썬이 열려 있는 파일을 정리하기도 하지만, 직접 파일을 닫아 주는 습관을 들이는 것이 좋다.
특히 파일이 계속 열려 있으면 파일을 다시 사용하거나 다른 프로그램에서 접근할 때 문제가 발생할 수 있다.
현재 디렉터리가 아닌 특정 위치에 파일을 만들 수도 있다.
예를 들어
f = open("C:/doit/새파일.txt", "w")
f.close()
라고 작성하면
C:/doit/
폴더에 파일이 생성된다.
단,
C:/doit
폴더 자체가 존재하지 않는다면 오류가 발생할 수 있다.
\ 주의하기Windows에서는 보통 경로가 다음처럼 보인다.
C:\doit\test.txt
하지만 파이썬 문자열에서 \는 이스케이프 문자에 사용된다.
예를 들어
\n → 줄바꿈
\t → 탭
따라서 다음과 같은 경로는 의도치 않게 해석될 수 있다.
"C:\note\test.txt"
여기에는
\n
\t
가 포함되어 있기 때문이다.
/ 사용가장 간단한 방법이다.
"C:/doit/test.txt"
\\ 사용역슬래시를 두 번 작성한다.
"C:\\doit\\test.txt"
문자열 앞에 r을 붙인다.
r"C:\doit\test.txt"
정리하면
"C:/doit/test.txt"
또는
"C:\\doit\\test.txt"
또는
r"C:\doit\test.txt"
처럼 사용할 수 있다.
파일에 실제 내용을 작성할 때는
write()
를 사용한다.
예를 들어
f = open("새파일.txt", "w")
f.write("Hello Python")
f.close()
를 실행하면 새파일.txt에
Hello Python
이 저장된다.
f = open("새파일.txt", "w")
for i in range(1, 11):
data = f"{i}번째 줄입니다.\n"
f.write(data)
f.close()
파일 내용은 다음과 같다.
1번째 줄입니다.
2번째 줄입니다.
3번째 줄입니다.
4번째 줄입니다.
5번째 줄입니다.
6번째 줄입니다.
7번째 줄입니다.
8번째 줄입니다.
9번째 줄입니다.
10번째 줄입니다.
여기에서
f.write(data)
가 실제 파일에 데이터를 기록하는 역할을 한다.
print()와 write() 차이다음 코드는
for i in range(1, 11):
data = f"{i}번째 줄입니다.\n"
print(data)
내용을 모니터에 출력한다.
반면
f.write(data)
는 내용을 파일에 출력한다.
즉,
| 함수 | 출력 위치 |
|---|---|
print() | 모니터 |
f.write() | 파일 |
print()
↓
모니터
write()
↓
파일
파일에 데이터를 저장했다면 다시 읽을 수도 있다.
파이썬에서는 대표적으로
readline()
readlines()
read()
을 사용할 수 있다.
또한 파일 객체를 for 문에 직접 넣어 읽는 방법도 있다.
readline()은 파일에서 한 줄씩 읽는다.
f = open("새파일.txt", "r")
line = f.readline()
print(line)
f.close()
파일의 내용이
1번째 줄입니다.
2번째 줄입니다.
3번째 줄입니다.
라면
f.readline()
을 한 번 실행했을 때
1번째 줄입니다.
를 읽는다.
line1 = f.readline()
line2 = f.readline()
첫 번째 실행
1번째 줄입니다.
두 번째 실행
2번째 줄입니다.
즉, 실행할 때마다 다음 줄을 읽는다.
readline()
↓
1번째 줄
readline()
↓
2번째 줄
readline()
↓
3번째 줄
while 문을 사용하면 파일 끝까지 읽을 수 있다.
f = open("새파일.txt", "r")
while True:
line = f.readline()
if not line:
break
print(line)
f.close()
readline()은 더 이상 읽을 내용이 없으면
''
즉, 빈 문자열을 반환한다.
따라서
if not line:
break
를 만나 반복문이 종료된다.
readline()
↓
한 줄 읽기
↓
내용 있음?
┌───────┴───────┐
Yes No
↓ ↓
출력 break
↓
다음 줄
파일의 각 줄에는 보통 줄바꿈 문자
\n
이 포함되어 있다.
예를 들어 실제 line 값은
"1번째 줄입니다.\n"
이다.
그런데 print()도 기본적으로 마지막에 줄바꿈을 한다.
즉,
파일의 \n
+
print의 \n
가 되어 출력 사이에 빈 줄이 보일 수 있다.
이번에는
readlines()
이다.
이름을 자세히 보면
readline
readlines
↑
s
차이가 있다.
readlines()는 파일의 모든 줄을 읽어 리스트로 반환한다.
f = open("새파일.txt", "r")
lines = f.readlines()
print(lines)
f.close()
예를 들어 파일이
1번째 줄입니다.
2번째 줄입니다.
3번째 줄입니다.
이라면 결과는 다음과 비슷하다.
[
"1번째 줄입니다.\n",
"2번째 줄입니다.\n",
"3번째 줄입니다.\n"
]
즉,
readlines()
↓
파일 전체 읽기
↓
각 줄을 리스트 요소로 저장
f = open("새파일.txt", "r")
lines = f.readlines()
for line in lines:
print(line)
f.close()
lines가 리스트이므로 for 문으로 하나씩 꺼내 사용할 수 있다.
| 함수 | 결과 |
|---|---|
readline() | 한 줄을 문자열로 읽음 |
readlines() | 모든 줄을 리스트로 읽음 |
쉽게 기억하면
readline
↓
한 줄
readlines
↓
여러 줄
↓
리스트
이다.
readlines()로 파일을 읽으면 각 문자열 끝에
\n
이 들어 있을 수 있다.
lines = [
"1번째 줄입니다.\n",
"2번째 줄입니다.\n"
]
이 줄바꿈 문자를 제거하고 싶다면
strip()
을 사용할 수 있다.
f = open("새파일.txt", "r")
lines = f.readlines()
for line in lines:
line = line.strip()
print(line)
f.close()
결과
1번째 줄입니다.
2번째 줄입니다.
3번째 줄입니다.
strip()은 문자열의 양쪽에 있는 공백이나 줄바꿈 문자 등을 제거한다.
text = " Python "
print(text.strip())
결과
Python
파일 처리에서는 특히
\n
제거에 자주 사용한다.
⭐ 파일을 한 줄씩 읽을 때
strip()은 매우 자주 사용된다.
read()는 파일의 전체 내용을 하나의 문자열로 읽는다.
f = open("새파일.txt", "r")
data = f.read()
print(data)
f.close()
예를 들어 파일 내용이
Hello
Python
Study
라면 data는 개념적으로
"Hello\nPython\nStudy"
와 같은 하나의 문자열이 된다.
즉,
read()
↓
파일 전체
↓
하나의 문자열
| 함수 | 읽는 범위 | 반환 자료형 |
|---|---|---|
readline() | 한 줄 | 문자열 str |
readlines() | 모든 줄 | 리스트 list |
read() | 전체 내용 | 문자열 str |
파일 객체 자체를 for 문과 함께 사용할 수도 있다.
f = open("새파일.txt", "r")
for line in f:
print(line)
f.close()
파일 객체는 줄 단위로 반복할 수 있기 때문에
for line in f:
라고 작성하면 한 줄씩 순서대로 읽는다.
더 깔끔하게 작성하면
f = open("새파일.txt", "r")
for line in f:
print(line.strip())
f.close()
처럼 사용할 수도 있다.
앞에서 배운 w 모드는 기존 내용을 지운다는 문제가 있다.
예를 들어 파일에
1번째 줄입니다.
2번째 줄입니다.
가 저장되어 있는 상태에서
f = open("새파일.txt", "w")
를 사용하면 기존 내용이 없어질 수 있다.
기존 내용을 유지하면서 새로운 내용을 추가하려면
a
모드를 사용한다.
f = open("새파일.txt", "a")
for i in range(11, 20):
data = f"{i}번째 줄입니다.\n"
f.write(data)
f.close()
그러면 기존 파일의 마지막 부분부터 새로운 내용이 추가된다.
기존 내용
1번째 줄입니다.
2번째 줄입니다.
...
10번째 줄입니다.
↓ a 모드
11번째 줄입니다.
12번째 줄입니다.
...
19번째 줄입니다.
w와 a의 차이이 부분은 매우 중요하다.
w기존 내용
AAAA
BBBB
↓ w
기존 내용 삭제
↓
새 내용
CCCC
a기존 내용
AAAA
BBBB
↓ a
AAAA
BBBB
CCCC ← 뒤에 추가
따라서
기존 내용을 유지해야 한다면
w가 아니라a를 사용해야 한다.
지금까지 파일을 사용할 때 계속 다음과 같이 작성했다.
f = open("foo.txt", "w")
f.write("Life is too short, you need python")
f.close()
항상
open()
↓
파일 작업
↓
close()
가 필요했다.
그런데 with 문을 사용하면 close()를 직접 작성하지 않아도 된다.
다음과 같이 작성한다.
with open("foo.txt", "w") as f:
f.write("Life is too short, you need python")
구조는 다음과 같다.
with open("파일이름", "모드") as 파일객체:
파일 작업
예를 들어
with open("test.txt", "w") as f:
f.write("Hello Python")
with 블록을 벗어나면 파일이 자동으로 닫힌다.
따라서 따로
f.close()
를 작성하지 않아도 된다.
f = open("test.txt", "w")
f.write("Hello")
f.close()
with open("test.txt", "w") as f:
f.write("Hello")
훨씬 간결하다.
파일 처리에서는 보통 다음 형태를 많이 사용한다.
with open("test.txt", "w") as f:
f.write("Hello Python")
with open("test.txt", "r") as f:
data = f.read()
print(data)
close()를 깜빡하는 실수를 줄일 수 있기 때문에 편리하다.
파일 객체의
closed
속성을 사용하면 파일이 닫혀 있는지 확인할 수 있다.
with open("foo.txt", "w") as f:
f.write("Hello")
print(f.closed)
with 블록 안에서는 파일이 아직 열려 있으므로
False
가 나온다.
그리고 블록 밖에서
print(f.closed)
를 실행하면
True
가 나온다.
즉,
with 블록 안
↓
f.closed = False
↓
파일 열려 있음
with 블록 밖
↓
f.closed = True
↓
파일 닫힘
이다.
다음 코드를 살펴보자.
with open("test.txt", "w") as f:
content = "Hello, Python!"
f.write(content)
print(content)
결과
Hello, Python!
content는 with 문 내부에서 만들었지만 블록 밖에서도 사용할 수 있다.
파이썬에서
if
for
while
with
와 같은 블록은 새로운 지역 변수 범위를 만들지 않기 때문이다.
f도 사용할 수 있을까?변수 자체는 존재하지만 파일은 이미 닫힌 상태이다.
with open("test.txt", "w") as f:
f.write("Hello")
with가 끝난 후
print(f.closed)
는 가능하다.
결과
True
하지만
f.write("Python")
처럼 닫힌 파일에 다시 쓰려고 하면 오류가 발생한다.
즉,
with 블록 종료
↓
f 변수 자체는 존재
↓
하지만 파일은 닫혀 있음
↓
read(), write() 사용 불가
이다.
파일을 다룰 때 특히 한글이 포함되어 있다면 인코딩에 주의해야 한다.
운영체제나 환경에 따라 기본 문자 인코딩이 달라질 수 있기 때문이다.
따라서 파일을 읽고 쓸 때 명시적으로
encoding="utf-8"
을 지정하는 것이 좋다.
한글 파일을 작성해 보자.
with open("한글파일.txt", "w", encoding="utf-8") as f:
f.write("안녕하세요, 파이썬!")
읽을 때도 동일하게 UTF-8을 지정할 수 있다.
with open("한글파일.txt", "r", encoding="utf-8") as f:
content = f.read()
print(content)
결과
안녕하세요, 파이썬!
컴퓨터는 우리가 보는
A
B
가
나
안녕하세요
같은 문자를 그대로 저장하는 것이 아니라 숫자로 변환하여 저장한다.
이때
문자를 어떤 방식으로 숫자로 표현할 것인지 정해 놓은 규칙
을 인코딩(Encoding) 이라고 한다.
UTF-8은 한글을 포함해 다양한 언어의 문자를 표현할 수 있어 널리 사용되는 문자 인코딩 방식이다.
따라서 파일을 다룰 때
encoding="utf-8"
을 명시해 두면 서로 다른 환경에서 파일을 처리할 때 발생할 수 있는 문자 깨짐 문제를 줄이는 데 도움이 된다.
처음 배울 때는
f = open("test.txt", "w")
f.write("Hello Python")
f.close()
로 이해하고,
실제로 사용할 때는
with open("test.txt", "w", encoding="utf-8") as f:
f.write("Hello Python")
형태를 익혀 두면 좋다.
파일 전체를 읽으려면
with open("test.txt", "r", encoding="utf-8") as f:
data = f.read()
print(data)
한 줄씩 읽으려면
with open("test.txt", "r", encoding="utf-8") as f:
for line in f:
print(line.strip())
처럼 사용할 수 있다.
| 모드 | 의미 | 기존 파일 내용 |
|---|---|---|
r | 읽기 | 유지 |
w | 쓰기 | ⚠️ 삭제 후 작성 |
a | 추가 | 유지 후 뒤에 추가 |
| 함수 | 설명 |
|---|---|
open() | 파일 열기 |
close() | 파일 닫기 |
write() | 파일에 내용 쓰기 |
readline() | 한 줄 읽기 |
readlines() | 모든 줄을 리스트로 읽기 |
read() | 전체 내용을 문자열로 읽기 |
strip() | 앞뒤 공백 및 줄바꿈 문자 제거 |
w와 aopen("test.txt", "w")
기존 내용 삭제
↓
새로운 내용 작성
반면
open("test.txt", "a")
기존 내용 유지
↓
마지막에 새로운 내용 추가
따라서 기존 데이터를 보존해야 한다면 반드시 주의해야 한다.
f.readline()
"1번째 줄입니다.\n"
f.readlines()
[
"1번째 줄입니다.\n",
"2번째 줄입니다.\n",
"3번째 줄입니다.\n"
]
f.read()
"1번째 줄입니다.\n2번째 줄입니다.\n3번째 줄입니다.\n"
따라서
readline() → 한 줄 → str
readlines() → 여러 줄 → list
read() → 전체 → str
이라고 기억하면 된다.
기존 방식
f = open("test.txt", "w")
f.write("Hello")
f.close()
with 방식
with open("test.txt", "w") as f:
f.write("Hello")
with를 사용하면 블록이 끝날 때 파일을 자동으로 닫아 준다.
with 시작
↓
파일 open
↓
파일 작업
↓
with 종료
↓
자동 close
💡 파일 입출력에서는
open(),r/w/a,read(),write()의 역할을 먼저 이해하고, 실제 코드를 작성할 때는with open(...) as f:형태를 익숙하게 사용하는 것이 중요하다.