본문으로 건너뛰기

파일 읽어 모으기

파이썬 목차파일과 모듈레슨 50 / 59

목차

파일에서 글을 한 줄씩 읽을 때는 with open(파일이름, 'r') as f: 안에서 **for line in f:**로 꺼내고 **line.strip()**으로 줄 끝의 \n을 떼어 냅니다.

파일에 쓰기에서는 줄을 나눌 때마다 문자열 끝에 \n을 붙여서 저장했습니다. 따라서 파일에서 한 줄을 다시 꺼내 오면 그 줄 끝에도 여전히 \n이 붙어 있습니다. 여기에 print()가 자기 줄바꿈을 한 번 더 넣으면 줄마다 빈 줄이 하나씩 끼어들고, 숫자로 바꾸거나 단어를 비교할 때도 끝의 \n이 방해가 됩니다. 읽은 줄에서 .strip()으로 \n을 먼저 떼어 내는 까닭이 여기에 있습니다.

10단계 중 1단계. memo.txt에 저장된 두 줄('사과\n', '바나나\n')을 한 줄씩 꺼내 .strip()으로 줄바꿈을 떼고 출력합니다.

1한 줄씩 꺼내 읽고 strip()으로 다듬기

읽기 모드('r')로 연 파일 f를 for line in f:에 넣으면 파일의 첫 줄부터 끝 줄까지 한 줄씩 차례로 꺼내 줍니다. 먼저 memo.txt에 두 줄을 저장해 두고 읽어 보겠습니다.

with open('memo.txt', 'w') as f:
    f.write('사과\n바나나\n')
with open('memo.txt', 'r') as f:
    for line in f:
        clean = line.strip()
        print(clean)
실행 결과
사과
바나나

line에는 '사과\n'과 '바나나\n'이 차례로 들어오지만, 문자열 메서드에서 배운 line.strip()이 양끝의 공백과 줄바꿈(\n)을 떼어 내어 '사과'와 '바나나'만 깔끔하게 찍힙니다.

만약 .strip()을 쓰지 않고 print(line)을 바로 부르면 어떻게 될까요? 실행 결과를 먼저 맞혀 보세요.

with open('m.txt', 'w') as f:
    f.write('사과\n바나나\n')
with open('m.txt', 'r') as f:
    for line in f:
        print(line)
실행 결과 보기
실행 결과
사과

바나나

예상과 다르면 그곳이 배울 곳입니다. '사과\n' 자체가 한 번 줄을 바꾸고, print()가 끝에 또 줄을 바꾸어 '사과'와 '바나나' 사이에 빈 줄이 하나 더 생겼습니다.

2한꺼번에 읽기(read)와 쪼개어 계산하기

파일이 짧아서 내용 전체를 문자열 하나로 통째로 읽고 싶을 때는 f.read()를 씁니다. 반대로 줄마다 '사과,1000'처럼 여러 값이 적혀 있을 때는 한 줄씩 꺼내 .strip()과 .split(',')으로 쪼갭니다.

읽는 방법돌려주는 값언제 쓰는가
for line in f:바퀴마다 한 줄 문자열 ('사과\n')줄마다 다듬거나 계산할 때
f.read()파일 전체를 합친 문자열 하나파일 전체를 한 번에 볼 때

줄마다 과일 이름과 가격이 쉼표로 적힌 파일을 읽어 가격의 합을 구해 보겠습니다.

with open('item.txt', 'w') as f:
    f.write('사과,1000\n')
    f.write('배,2000\n')
total = 0
with open('item.txt', 'r') as f:
    for line in f:
        s = line.strip()
        p = s.split(',')
        total += int(p[1])
print('합:', total)
실행 결과
합: 3000

line.strip()으로 끝의 \n을 먼저 떼어 내고 .split(',')으로 쪼개면 p는 ['사과', '1000']이 됩니다. 그중 1번 칸 p[1]을 int()로 바꾸어 더했습니다.

예제

없는 파일을 열 때 멈추지 않게 하기

'r' 모드는 'w' 모드와 달리 파일이 없으면 새로 만들지 않고 FileNotFoundError를 내며 멈춥니다. try와 except로 감싸면 파일이 없을 때도 친절한 안내를 찍을 수 있습니다.

try:
    with open('x', 'r') as f:
        print(f.read())
except FileNotFoundError:
    print('파일이 없습니다')
실행 결과
파일이 없습니다

자주 틀리는 곳

1. .strip()을 빼먹어 줄바꿈(\n)이 남는다

틀린 생각: 파일에 '사과'라고 적었으니 for line in f:로 꺼낸 line도 '사과'와 같다.

눈으로 파일을 열었을 때는 줄바꿈 기호가 보이지 않아 그렇게 생각하기 쉽지만, 파일에서 읽은 line 끝에는 늘 '\n'이 붙어 있어 '사과'와 비교하면 False가 됩니다.

with open('w.txt', 'w') as f:
    f.write('사과\n')
with open('w.txt', 'r') as f:
    for line in f:
        s = line.strip()
        print(line == '사과')
        print(s == '사과')
실행 결과
False
True

'사과\n' == '사과'는 False이고, .strip()으로 '\n'을 떼어 낸 뒤에야 True가 됩니다.

맞는 규칙: 파일에서 한 줄씩 꺼내 비교하거나 출력할 때는 line.strip()으로 끝의 '\n'을 먼저 떼어 냅니다.

2. 이미 끝까지 읽은 f를 닫지 않고 또 읽으려 한다

틀린 생각: 같은 with 블록 안에서 for line in f:나 f.read()를 두 번 쓰면 처음부터 두 번 읽어 준다.

파일 f는 리스트가 아니라 어디까지 읽었는지 가리키는 책갈피와 같아서, 한 번 끝까지 읽고 나면 책갈피가 파일 맨 끝에 머물러 두 번째에는 빈 문자열 ''만 나옵니다.

with open('r.txt', 'w') as f:
    f.write('첫줄\n')
with open('r.txt', 'r') as f:
    print('1차:', len(f.read()))
    print('2차:', len(f.read()))
실행 결과
1차: 3
2차: 0

첫 번째 f.read()에서 세 글자('첫줄\n')를 끝까지 다 읽었기 때문에 두 번째 f.read()는 빈 문자열(길이 0)을 돌려줍니다.

맞는 규칙: 읽은 줄들을 여러 번 써야 할 때는 처음 읽을 때 리스트에 모아 두거나 with open(...)으로 다시 엽니다.

3. 없는 파일을 'r' 모드로 열면 빈 파일이 생길 것이라 생각한다

틀린 생각: 'w' 모드가 없는 파일을 새로 만들어 주듯 'r' 모드도 없는 파일을 빈 채로 열어 준다.

읽기 모드('r')는 이미 있는 파일을 읽는 모드라, 파일 이름이 틀렸거나 파일이 없으면 바로 FileNotFoundError로 멈춥니다.

try:
    open('none.txt', 'r')
except FileNotFoundError:
    print('FileNotFoundError!')
실행 결과
FileNotFoundError!

맞는 규칙: 'r'로 열기 전에 파일 이름이 맞는지 확인하거나, 파일이 없을 수도 있을 때는 except FileNotFoundError:⁠로 감쌉니다.

확인 문제

1. 다음 코드를 실행하면 무엇이 출력될까요?

with open('n.txt', 'w') as f:
    f.write('10\n20\n30\n')
total = 0
with open('n.txt', 'r') as f:
    for line in f:
        s = line.strip()
        total += int(s)
print(total)
힌트

세 줄 '10', '20', '30'을 한 줄씩 꺼내 정수로 바꾸어 total에 더합니다.

정답
실행 결과
60

바퀴마다 10, 20, 30이 더해져 60이 출력됩니다.

2. w.txt에서 한 줄씩 꺼내 끝의 줄바꿈을 떼고 세 글자 이상인 단어만 출력하려고 합니다. 빈칸을 채우세요.

with open('w.txt', 'r') as f:
    for line in f:
        w = line._______()
        if len(w) >= 3:
            print(w)
힌트

문자열 양끝의 공백과 줄바꿈(\n)을 떼어 내는 문자열 메서드입니다.

정답

strip입니다 (w = line.strip()). strip()을 빼먹으면 줄 끝의 '\n'까지 글자 수에 더해져 두 글자 단어('사과\n')도 길이가 3이 되어 버립니다.

3. 다음 코드는 data.txt에 적힌 '가\n나\n'를 읽어 출력하려 한 것인데, 두 번째 for 반복문에서 아무것도 찍히지 않습니다. 왜 그런지 설명해 보세요.

with open('data.txt', 'w') as f:
    f.write('가\n나\n')
with open('data.txt', 'r') as f:
    for line in f:
        pass
    for line in f:
        print(line.strip())
힌트

첫 번째 for line in f:가 끝났을 때 파일의 읽기 위치(책갈피)가 어디에 가 있는지 생각해 보세요.

정답

첫 번째 for line in f:에서 이미 파일 끝까지 다 읽었기 때문에, 같은 f로 두 번째 for를 돌리면 더 꺼낼 줄이 없습니다. 다시 읽으려면 새로운 with open(...) 블록으로 열어야 합니다.

아래 코드에서 line.strip()을 line으로 바꾸면 왜 줄 사이에 빈 줄이 생기는지 직접 비교해 보세요.

처음 펼 때 약 6MB를 받습니다.컴퓨터에서 해 보기

끝까지 내려오면 저절로 표시됩니다. 이 기기에만 저장합니다.

파이썬 목차로