HOWTO · Python

파이썬에서 파일에서 특정 줄을 읽는 방법

파일에서 특정 줄을 읽는 방법을 알아보세요. 작은 파일에는 `fileobject.readlines()`, 같은 파일의 줄을 반복해서 조회할 때는 `linecache`, 큰 파일을 순차적으로 읽을 때는 `enumerate()`를 사용할 수 있습니다. `linecache`는 파일 내용을 캐시하므로 메모리를 사용합니다.

이 페이지의 내용

Python 텍스트 파일에서 특정 줄을 하나 이상 읽으려면 먼저 줄 번호가 사람 기준인지 Python 코드 기준인지 정하세요. 사람 기준 줄 번호는 보통 1부터 시작하지만, 리스트 인덱스는 0부터 시작합니다. 작은 파일에서는 readlines()로 모든 줄을 불러와 인덱스로 바로 접근할 수 있습니다. 큰 파일에서는 enumerate()로 줄을 순차적으로 읽을 수 있습니다. 같은 파일의 여러 줄을 반복해서 요청할 때는 linecache로 줄 번호를 지정해 조회할 수 있습니다. 파일 데이터를 캐시하므로 메모리를 일정하게 유지하는 방법은 아닙니다.

먼저 줄 번호 기준을 정하세요

사람이 3번째 줄을 요청하면 해당 리스트 인덱스는 3 - 1, 즉 2입니다. enumerate()도 기본적으로 인덱스 0부터 시작합니다. 반면 linecache.getline(path, 3)에는 사람 기준 줄 번호인 3을 전달합니다. 이 기준들을 명확히 구분하면 인덱스를 하나씩 잘못 계산하는 실수를 막을 수 있습니다. 텍스트 줄에는 끝의 줄바꿈 문자가 포함되는 경우가 많으므로, 공백 없이 표시하거나 비교해야 할 때만 제거하세요.

작은 파일에서 readlines()로 필요한 줄 읽기

readlines()는 각 줄을 담은 리스트를 반환하며, 줄바꿈 문자가 있으면 함께 포함합니다. 파일이 메모리에 충분히 들어가고 여러 위치에 접근할 수 있어야 할 때 편리합니다. 다음 독립 실행 예제는 임시 텍스트 파일을 만들고 세 번째 줄을 출력합니다.

이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.

from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as folder:
    path = Path(folder) / "notes.txt"
    path.write_text("first\nsecond\nthird\nfourth\n", encoding="utf-8")
    with path.open(encoding="utf-8") as file:
        lines = file.readlines()
    print(lines[2].rstrip("\n"))

사람 기준 줄 번호 first_line부터 last_line까지를 포함해 읽으려면 슬라이스 lines[first_line - 1:last_line]을 사용하세요. 슬라이스의 끝 인덱스는 결과에 포함되지 않으므로, 사람 기준 마지막 줄 번호를 끝 인덱스로 그대로 사용할 수 있습니다. 요청한 줄이 없을 수도 있다면 인덱싱 전에 요청 인덱스가 len(lines) 범위 안에 있는지 확인하세요.

큰 파일에서 enumerate()로 필요한 줄 읽기

파일을 직접 반복하면 모든 줄을 리스트로 만드는 과정을 피할 수 있습니다. enumerate(file)은 줄을 읽을 때마다 0부터 시작하는 인덱스를 제공합니다. 사람 기준 줄 번호를 표시하려면 여기에 1을 더하세요. 뒤쪽 줄에 도달하려면 앞선 줄을 지나야 하므로, 이 방법은 멀리 있는 줄로 바로 이동하기보다 메모리 사용을 줄이는 데 유용합니다.

이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.

from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as folder:
    path = Path(folder) / "events.txt"
    path.write_text("start\nready\nconnected\nfinished\n", encoding="utf-8")
    wanted = {2, 4}
    with path.open(encoding="utf-8") as file:
        for line_number, line in enumerate(file, start=1):
            if line_number in wanted:
                print(line_number, line.rstrip("\n"))
            if line_number >= max(wanted):
                break

여기서는 start=1을 지정해 반복문의 변수가 사람 기준 줄 번호가 되도록 합니다. 이렇게 하면 줄을 선택하는 조건을 더 읽기 쉽게 작성할 수 있습니다. 파일에 요청한 줄 수만큼 줄이 없더라도 반복문은 끝나며, 존재하지 않는 줄에 대해서는 출력되지 않습니다.

반복해서 줄에 접근할 때 linecache 사용하기

같은 파일에서 1부터 시작하는 줄 번호로 여러 번 조회할 때는 linecache.getline(path, line_number)을 사용하세요. 이 함수는 해당 줄을 텍스트로 반환하며, 줄바꿈 문자가 있으면 함께 포함합니다. 요청한 줄이 없으면 빈 문자열을 반환합니다. linecache는 재사용할 수 있도록 파일 내용을 캐시하므로 같은 파일을 반복해서 조회할 때 편리할 수 있지만, 캐시 데이터는 메모리를 사용합니다.

이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.

import linecache
from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as folder:
    path = Path(folder) / "report.txt"
    path.write_text("header\nalpha\nbeta\n", encoding="utf-8")
    line = linecache.getline(str(path), 2)
    print(line.rstrip("\n"))
    linecache.clearcache()

예제 끝의 명시적인 clearcache() 호출은 캐시된 항목을 해제합니다. 파일이 변경될 수 있다면 캐시의 최신 상태도 고려해야 합니다. 프로그램에서 파일을 변경한 뒤 캐시 데이터를 버리고 새로 조회하려면 먼저 캐시를 비우세요.

범위, 없는 줄, 메모리 한도 처리하기

파일 전체를 메모리에 담는 부담보다 적당한 크기의 파일에서 바로 접근하는 편의가 더 중요하다면 readlines()를 선택하세요. 큰 파일을 순차적으로 처리하거나 특정 줄을 찾은 뒤 읽기를 멈추려면 enumerate()를 선택할 수 있습니다. 다만 뒤쪽 줄을 찾으려면 앞선 줄을 읽어야 합니다. 캐시 사용이 괜찮고 번호로 된 줄을 반복해서 요청한다면 linecache를 선택하세요. 파일 끝을 넘는 줄을 가져올 수 있는 방법은 없습니다. 리스트 인덱싱은 IndexError를 발생시키고, 반복문은 해당 줄을 찾지 못하며, getline()은 빈 문자열을 반환합니다. 요청을 검증하거나 프로그램의 필요에 맞게 결과를 처리하세요.

텍스트 파일은 읽기 모드로 여세요. 파일이 블록 끝에서 닫히도록 with 문을 사용하는 것이 좋습니다. 파일 인코딩을 알고 있다면 인코딩을 지정하세요. 파일 전체를 메모리에 불러오면 줄 수와 줄 길이가 늘어날수록 상당한 메모리를 사용할 수 있습니다. 모든 컴퓨터와 작업에 적용되는 보편적인 파일 크기 기준은 없습니다. 스트리밍은 읽기 반복문이 보유하는 줄 수를 제한하지만, 선택한 줄을 모아 두면 그 데이터는 여전히 메모리를 차지합니다. 따라서 고정된 크기나 속도 주장보다 접근 방식과 사용 가능한 메모리를 기준으로 방법을 선택하세요.