HOWTO · Python

Python에서 목록으로 텍스트 파일 읽기

이 튜토리얼은 텍스트 파일을 파이썬 목록으로 읽는 방법을 보여줍니다.

이 페이지의 내용

텍스트 파일을 Python 리스트로 읽으려면 먼저 각 항목이 무엇을 나타내야 하는지 정하세요. 실제 줄, 구분자로 나뉜 필드, 행, 숫자 값 중 무엇이 필요한지에 따라 방법이 달라집니다. 일반 텍스트에서 readlines()는 파일을 읽어 가며 줄마다 문자열 하나를 결과 리스트에 쌓고, 줄 끝 문자가 있으면 이를 문자열에 포함합니다. 이때 파일 전체를 별도의 문자열로 보관하지는 않습니다. 반면 read() 다음에 splitlines()를 호출하면 파일 전체 텍스트를 메모리에 둔 채 줄 문자열 리스트를 만듭니다. 큰 파일을 처리만 하면 되는 경우에는 모든 줄을 모으는 대신 파일을 순회하세요.

아래 예제는 각각 작은 입력 파일을 직접 만듭니다. 임시 경로를 실제 파일 경로로 바꾸어 사용할 수 있습니다. 예제는 설명을 위한 것이며 이 작성 단계에서는 실행되지 않았습니다.

readlines()로 줄 읽기

readlines()는 파일의 각 줄을 요소로 갖는 리스트를 반환합니다. 줄 끝 문자가 있으면 보통 각 문자열에 포함되므로 리스트를 표시할 때 \n으로 보일 수 있습니다. 컨텍스트 관리자는 리스트를 읽은 뒤 파일을 닫습니다.

다음 예제를 실행하세요.
이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.

from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as directory:
    path = Path(directory) / "notes.txt"
    path.write_text("First line\nSecond line\nThird line\n", encoding="utf-8")
    with path.open(encoding="utf-8") as file:
        lines = file.readlines()
    print(lines)

결과 리스트에는 줄 끝 문자를 포함한 모든 줄이 메모리에 들어 있습니다. 원래 줄 문자열을 유지해야 하는 작은 파일에 편리합니다. 처리만 하면 되는 큰 파일이라면 모든 줄을 저장하는 대신 큰 파일 섹션의 반복문을 사용하세요.

리스트 컴프리헨션으로 줄을 읽고 정리하기

텍스트 파일을 순회하면 한 번에 한 줄씩 읽습니다. 리스트 컴프리헨션으로 줄을 리스트에 담을 수 있으며, rstrip("\r\n")은 텍스트에 포함된 공백은 그대로 두고 줄 끝 문자만 제거합니다.
이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.

from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as directory:
    path = Path(directory) / "names.txt"
    path.write_text(" Ada \nLin\n", encoding="utf-8")
    with path.open(encoding="utf-8") as file:
        names = [line.rstrip("\r\n") for line in file]
    print(names)

strip()도 사용할 수 있지만 줄 양쪽의 공백을 모두 제거하므로 줄 안에서 의미가 있는 공백도 사라집니다. 컴프리헨션이 입력을 조금씩 읽더라도 최종 리스트에는 정리한 문자열이 모두 메모리에 들어갑니다. 리스트가 필요하고 파일이 사용 가능한 메모리에 들어갈 때 이 방법을 선택하세요.

파일 전체를 읽고 줄로 나누기

전체 텍스트를 먼저 읽은 다음 줄로 나누려면 read() 다음에 splitlines()를 사용하세요. splitlines()는 일반적인 줄 경계를 인식하며 반환하는 문자열에 경계 문자를 포함하지 않습니다.
이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.

from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as directory:
    path = Path(directory) / "poem.txt"
    path.write_text("Red\nBlue\nGold\n", encoding="utf-8")
    with path.open(encoding="utf-8") as file:
        content = file.read()
    lines = content.splitlines()
    print(lines)

파일 전체 문자열과 결과 리스트가 모두 메모리를 사용하므로 매우 큰 입력에는 적합하지 않습니다. 줄 단위 작업이라면 컴프리헨션이나 반복문을 사용해 파일 전체를 문자열 하나로 먼저 읽어 두는 과정을 피할 수 있습니다.

큰 파일을 한 줄씩 처리하기

각 레코드를 독립적으로 처리할 수 있다면 파일 반복문 안에서 처리하고 작업에 필요한 상태만 유지하세요. 이 예제는 파일 내용을 리스트에 보관하지 않고 비어 있지 않은 줄의 수를 셉니다.
이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.

from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as directory:
    path = Path(directory) / "events.txt"
    path.write_text("login\nview\nlogout\n", encoding="utf-8")
    count = 0
    with path.open(encoding="utf-8") as file:
        for line in file:
            if line.strip():
                count += 1
    print(count)

이 방법은 현재 줄과 작은 카운터만 유지하므로 메모리 사용량을 제한합니다. 리스트가 꼭 필요하다면 반복문에서 처리한 문자열을 추가할 수 있지만, 파일이 커질수록 리스트도 커집니다. 반복문을 사용한다고 해서 모든 데이터를 리스트에 모으는 작업의 메모리 효율이 좋아지는 것은 아닙니다. 존재하지 않는 경로를 열면 FileNotFoundError가 발생합니다. 올바른 경로를 지정하거나 애플리케이션에서 복구할 수 있도록 오류를 처리하세요.

split()으로 구분자 기준 텍스트 나누기

구분자가 하나로 정해진 단순한 형식이라면 텍스트를 읽고 해당 구분자를 인수로 split()을 호출하세요. 결과는 숫자가 아닌 문자열 리스트이며 구분자는 제거됩니다. 콜론으로 구분된 값처럼 형식이 일정한 텍스트에는 적합하지만 CSV의 인용 규칙이나 인용된 필드 안에 있는 구분자는 처리하지 못합니다.
이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.

from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as directory:
    path = Path(directory) / "colors.txt"
    path.write_text("red|green|blue", encoding="utf-8")
    with path.open(encoding="utf-8") as file:
        colors = file.read().split("|")
    print(colors)

각 필드를 명시적으로 다듬지 않으면 공백은 그대로 유지됩니다. 양쪽 공백이 데이터가 아니라 서식에 해당한다면 리스트 컴프리헨션에서 field.strip()을 사용할 수 있습니다.

csv.reader()로 구분된 행 읽기

CSV나 이와 비슷한 구분자 형식의 데이터에는 Python의 csv 모듈을 사용하세요. 이 모듈은 형식에 맞춰 인용된 구분자와 이스케이프된 따옴표를 파싱합니다. csv.reader()는 행마다 문자열 리스트 하나를 반환합니다. 모든 행을 메모리에 보관해야 할 때만 이 반복자를 리스트로 변환하세요. 큰 파일은 직접 순회해도 됩니다.
이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.

import csv
from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as directory:
    path = Path(directory) / "people.csv"
    path.write_text('name,city\n"Doe, Jane",Paris\nAlex,Rome\n', encoding="utf-8")
    with path.open(newline="", encoding="utf-8") as file:
        rows = list(csv.reader(file))
    print(rows)

입력에 머리글이 있으면 머리글을 포함해 각 행이 별도로 유지됩니다. 데이터 레코드만 필요하다면 머리글을 명시적으로 건너뛰거나 처리하세요. 첫 번째 행에 인덱스를 적용하는 것으로 여러 행이 있는 파일을 읽을 수는 없습니다. CSV 텍스트 파일을 열 때는 CSV 모듈의 권장 사항에 따라 newline=""을 사용하세요.

NumPy로 숫자 데이터 불러오기

행과 열이 일정한 숫자 텍스트 데이터라면 NumPy의 loadtxt()로 값을 파싱해 배열에 담을 수 있습니다. NumPy는 별도로 설치해야 하는 의존성입니다. 결과는 Python 리스트가 아니라 배열이므로 일반적인 중첩 리스트가 필요할 때는 tolist()를 호출하세요. 이 예제는 머리글이 없고 구분자 형식이 일정한 숫자 파일을 가정합니다.
이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.

from pathlib import Path
from tempfile import TemporaryDirectory

try:
    import numpy as np
except ImportError:
    print("Install NumPy to run this example.")
else:
    with TemporaryDirectory() as directory:
        path = Path(directory) / "measurements.csv"
        path.write_text("1.5,2.0\n3.5,4.0\n", encoding="utf-8")
        values = np.loadtxt(path, delimiter=",")
        print(values.tolist())

행마다 길이가 다르거나 텍스트가 들어 있거나 CSV 인용 규칙이 필요하다면 대신 csv.reader()를 사용하세요. 숫자 데이터에 배열 연산이 유용할 때는 NumPy를 선택하세요. NumPy의 파서와 배열 표현은 줄 문자열 리스트와 다릅니다.