본문 바로가기
C.W.K.
Stream
Lesson 06 of 06 · published

큰 파일과 임시 공간 — 조금씩 읽고 안전하게 끝내기

~18 min · streaming, tempfile, mmap, io

Level 0호기심
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete

파일이 메모리보다 클 수 있다고 가정해

텍스트 파일은 줄 단위로, 바이너리는 정한 크기의 조각으로 읽어. 10GB 파일에 인자 없는 read를 호출하면 10GB 전체를 올리려 해.

임시 파일과 디렉터리는 contextlib 수명으로

NamedTemporaryFile과 TemporaryDirectory는 충돌 없는 위치를 만들고 블록 뒤 정리해. 처리 중간물과 테스트에 고정된 임시 경로를 직접 만들 필요가 없어.

mmap과 메모리 파일

mmap은 파일을 가상 메모리에 연결해 실제로 만지는 쪽만 운영체제가 가져오게 하고 큰 파일의 임의 접근에 유리해. StringIO와 BytesIO는 파일 규약을 가진 메모리 객체라 시험과 출력 수집에 쓰여.

조금씩 읽고 임시 산출물에 완성한 뒤 바꾸는 설계는 메모리뿐 아니라 실패했을 때의 복구 지점도 지켜.

Code

큰 바이너리 파일을 조각으로 읽기·python
import io

# 가짜 파일 (데모용 메모리 backed)
big = io.BytesIO(b"xyz" * 1_000_000)        # 3MB

CHUNK = 4096
big.seek(0)
total = 0
while chunk := big.read(CHUNK):
    total += len(chunk)
print("읽은 바이트:", total)

# 또는 iterator 패턴
big.seek(0)
import functools
for chunk in iter(functools.partial(big.read, CHUNK), b""):
    pass
# iter() + sentinel — big.read(CHUNK) 가 b'' 반환할 때까지 호출
자동으로 정리되는 임시 공간·python
import tempfile
from pathlib import Path

# Named 파일 — 닫힐 때 자동 삭제
with tempfile.NamedTemporaryFile(suffix=".txt", delete=True) as tf:
    print("path:", tf.name)
    tf.write(b"hello world")
    tf.flush()
    # 여기 파일 디스크에 있음
    print("크기:", Path(tf.name).stat().st_size)
# 파일 사라짐

# 디렉토리 — 재귀 정리
with tempfile.TemporaryDirectory() as td:
    p = Path(td)
    (p / "a.txt").write_text("a", encoding="utf-8")
    (p / "b.txt").write_text("b", encoding="utf-8")
    print("내용:", list(p.iterdir()))
# 디렉토리 + 내용 사라짐
mmap으로 큰 파일 일부에 접근하기·python
import mmap
import tempfile
from pathlib import Path

# 샘플 파일
p = Path("/tmp/mmap_demo.txt")
p.write_bytes(b"hello world hello pippa hello universe")

with open(p, "r+b") as f:
    with mmap.mmap(f.fileno(), 0) as mm:
        # 검색
        idx = mm.find(b"pippa")
        print("발견 위치:", idx)

        # 슬라이스 — bytes 객체처럼
        print(mm[0:5])              # b'hello'

        # 변경 — 파일에 write 통과 (WRITE 권한)
        mm[0:5] = b"HOWDY"

# 변경 지속 확인 위해 다시 읽기
print(p.read_bytes()[:30])
p.unlink()
시험에 쓰는 메모리 파일 StringIO·python
import io
import csv

# 진짜 파일 안 쓰고 CSV 읽는 함수 테스트
fake = io.StringIO('''name,age
alice,30
bob,25
''')

rows = list(csv.DictReader(fake))
print(rows)
# [{'name': 'alice', 'age': '30'}, {'name': 'bob', 'age': '25'}]

# 바이너리도 같음
binary = io.BytesIO(b"\xDE\xAD\xBE\xEF")
print(binary.read(2))                # b'\xde\xad'

External links

Exercise

TemporaryDirectory 안에 pathlib로 파일 세 개를 만들고 블록 뒤 디렉터리가 사라지는지 확인해. 이어서 1MB 파일을 한 번에 읽기, 4KB씩 읽기, mmap으로 읽기의 세 방식으로 SHA-256을 계산해 모두 같은지 비교해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.