tarfile — tar 아카이브 파일 읽고 쓰기
tarfile — tar 아카이브 파일 읽고 쓰기
tarfile 모듈은 gzip, bz2, lzma 압축을 포함한 tar 아카이브를 읽고 쓸 수 있게 해줘요. .zip 파일은 zipfile 모듈을, 고수준 아카이빙 함수는 shutil을 쓰면 돼요.
몇 가지 특징:
- 해당 모듈이 있으면
gzip,bz2,compression.zstd,lzma로 압축된 아카이브를 읽고 써요. - POSIX.1-1988(ustar) 형식 읽기/쓰기 지원.
- GNU tar 형식(longname/longlink 확장 포함) 읽기/쓰기, 희소(sparse) 확장의 모든 변형은 읽기 전용 지원(희소 파일 복원 포함).
- POSIX.1-2001(pax) 형식 읽기/쓰기.
- 디렉터리, 일반 파일, 하드링크, 심볼릭 링크, fifo, 문자 장치, 블록 장치를 다루고 타임스탬프, 접근 권한, 소유자 같은 파일 정보를 얻고 복원할 수 있어요.
3.3에서 lzma 압축 추가. 3.12에서 아카이브를 필터로 추출하도록 변경(놀라운/위험한 기능을 제한하거나 완전히 신뢰함을 인정). 3.14에서 기본 추출 필터를 data로 설정(절대 경로 링크나 목적지 밖 경로 같은 위험한 기능 금지). 3.14에서 compression.zstd로 Zstandard 압축 지원 추가.
출처: Python 표준 라이브러리
본문
tarfile.open(name=None, mode='r', fileobj=None, bufsize=10240, **kwargs)
pathname name에 대한 TarFile 객체를 반환해요. mode는 'filemode[:compression]' 형태의 문자열이고 기본은 'r'이에요. 모드 조합:
| mode | 동작 |
|---|---|
'r' 또는 'r:*' |
투명한 압축으로 읽기용으로 열기(권장) |
'r:' |
압축 없이 전용 읽기 |
'r:gz' |
gzip 압축으로 읽기 |
'r:bz2' |
bzip2 압축으로 읽기 |
'r:xz' |
lzma 압축으로 읽기 |
'r:zst' |
Zstandard 압축으로 읽기 |
'x' 또는 'x:' |
압축 없이 독점 생성(이미 있으면 FileExistsError) |
'x:gz' |
gzip 압축으로 생성 |
'x:bz2' |
bzip2 압축으로 생성 |
'x:xz' |
lzma 압축으로 생성 |
'x:zst' |
Zstandard 압축으로 생성 |
'a' 또는 'a:' |
압축 없이 추가용으로 열기(없으면 생성) |
'w' 또는 'w:' |
압축 없는 쓰기 |
'w:gz' |
gzip 압축 쓰기 |
'w:bz2' |
bzip2 압축 쓰기 |
'w:xz' |
lzma 압축 쓰기 |
'w:zst' |
Zstandard 압축 쓰기 |
'a:gz', 'a:bz2', 'a:xz'는 불가능해요. 특정 (압축) 파일을 읽기에 부적합한 모드면 ReadError, 지원하지 않는 압축 방법이면 CompressionError가 발생해요. fileobj를 지정하면 name 대신 그 바이너리 파일 객체를 써요(위치 0에 있어야 해요).
'w:gz','x:gz','w|gz','w:bz2','x:bz2','w|bz2'모드에선compresslevel(기본9)을 받아요.'w:xz','x:xz','w|xz'에선preset으로 압축 수준을 받아요.'w:zst','x:zst','w|zst'에선level(및options,zstd_dict)을 받아요.
특수한 목적을 위한 두 번째 형식 'filemode|[compression]'이 있어요. 블록 스트림으로 데이터를 처리하는 TarFile 객체를 반환하며 임의 탐색(random seeking)이 없어요. sys.stdin.buffer, 소켓 파일 객체, 테이프 장치와 함께 써요. 가능한 모드: 'r|*', 'r|', 'r|gz', 'r|bz2', 'r|xz', 'r|zst', 'w|', 'w|gz', 'w|bz2', 'w|xz', 'w|zst'.
3.5에서 'x'(독점 생성) 모드, 3.6에서 path-like name, 3.12에서 스트림 compresslevel, 3.14에서 스트림 preset 추가.
class tarfile.TarFile — tar 아카이브 읽기/쓰기 클래스. 직접 쓰지 말고 tarfile.open()을 쓰세요.
tarfile.is_tarfile(name) — name이 tarfile 모듈이 읽을 수 있는 tar 아카이브 파일이면 True 반환. name은 str, 파일, 파일류 객체. 3.9에서 파일/파일류 객체 지원.
예외
exception tarfile.TarError— 모든tarfile예외의 기본 클래스.exception tarfile.ReadError— tar 아카이브를 열 때 모듈이 처리할 수 없거나 무효일 때 발생.exception tarfile.CompressionError— 압축 방법이 지원되지 않거나 데이터를 제대로 디코딩할 수 없을 때 발생.exception tarfile.StreamError— 스트림형TarFile객체에 전형적인 제약 때문에 발생.exception tarfile.ExtractError—TarFile.extract()에서 비치명적 오류일 때 발생하되TarFile.errorlevel == 2일 때만.exception tarfile.HeaderError—TarInfo.frombuf()가 무효한 버퍼를 받을 때 발생.exception tarfile.FilterError— 필터가 거부한 멤버를 위한 기본 클래스.tarinfo속성으로 거부된 멤버의TarInfo.exception tarfile.AbsolutePathError,OutsideDestinationError,SpecialFileError,AbsoluteLinkError,LinkOutsideDestinationError— 각각 절대 경로 멤버, 목적지 밖 멤버, 특수 파일(장치/파이프), 절대 경로 심볼릭 링크, 목적지 밖 심볼릭 링크 추출을 거부할 때 발생.exception tarfile.LinkFallbackError— 링크를 다른 아카이브 멤버 추출로 에뮬레이션할 때 그 멤버가 필터 위치에서 거부될 경우 발생. 거부를 일으킨 예외는BaseException.__context__에. 3.14 추가.
모듈 상수
tarfile.ENCODING— 기본 문자 인코딩: Windows에선'utf-8', 그 외엔sys.getfilesystemencoding()값.- 타입 상수:
REGTYPE,AREGTYPE(일반 파일),LNKTYPE(링크),SYMTYPE(심볼릭 링크),CHRTYPE(문자 특수 장치),BLKTYPE(블록 특수 장치),DIRTYPE(디렉터리),FIFOTYPE(FIFO 특수 장치),CONTTYPE(연속 파일),GNUTYPE_LONGNAME,GNUTYPE_LONGLINK,GNUTYPE_SPARSE. - 형식 상수:
USTAR_FORMAT(POSIX.1-1988),GNU_FORMAT(GNU tar),PAX_FORMAT(POSIX.1-2001),DEFAULT_FORMAT(현재PAX_FORMAT). 3.8에서 새 아카이브 기본 형식이GNU_FORMAT에서PAX_FORMAT으로 변경.
TarFile 객체
TarFile 객체는 tar 아카이브에 대한 인터페이스를 제공해요. 아카이브는 블록 시퀀스이고, 멤버(저장된 파일)는 헤더 블록과 데이터 블록으로 이루어져요. 각 멤버는 TarInfo 객체로 표현돼요. with 문의 컨텍스트 매니저로 쓸 수 있어요(블록이 끝나면 자동으로 닫힘). 3.2에서 컨텍스트 관리 프로토콜 지원.
class tarfile.TarFile(name=None, mode='r', fileobj=None, format=DEFAULT_FORMAT, tarinfo=TarInfo, dereference=False, ignore_zeros=False, encoding=ENCODING, errors='surrogateescape', pax_headers=None, debug=0, errorlevel=1, stream=False)
모든 인자는 선택이고 인스턴스 속성으로도 접근 가능해요.
name— 아카이브 경로(path-like 가능).fileobj가 주어지면 생략 가능.mode—'r'(기존 아카이브 읽기),'a'(추가),'w'(덮어쓰며 새로),'x'(없을 때만 새로).fileobj— 데이터 읽기/쓰기에 사용. 닫히지 않아요.format— 쓰기용 아카이브 형식. 읽을 땐 자동 감지.dereference—False면 심볼릭/하드 링크를 추가,True면 대상 파일 내용을 추가.ignore_zeros—False면 빈 블록을 아카이브 끝으로,True면 빈/무효 블록을 건너뛰며 멤버를 최대한 얻음(연결되거나 손상된 아카이브 읽기에만 유용).debug—0~3, 메시지는sys.stderr로.errorlevel— 추출 오류 처리 방법.encoding/errors— 아카이브 문자 인코딩과 변환 오류 처리. 기본(예:errors='surrogateescape')이 대부분에 맞아요.pax_headers—PAX_FORMAT일 때 pax 전역 헤더로 추가되는 문자열 딕셔너리.stream=True— 읽기 시 아카이브 파일 정보를 캐시하지 않아 메모리를 아껴요. 3.13 추가.
classmethod TarFile.open(...) — 대체 생성자. tarfile.open()은 이 classmethod의 단축이에요.
TarFile.getmember(name)— 멤버name의TarInfo객체 반환. 없으면KeyError. 멤버가 여러 번 있으면 마지막 발생을 최신으로 간주.TarFile.getmembers()— 아카이브 순서대로 멤버 리스트 반환.TarFile.getnames()— 멤버 이름 리스트 반환(getmembers()와 같은 순서).TarFile.list(verbose=True, *, members=None)— 목차를sys.stdout으로 출력.verbose가False면 이름만,True면ls -l비슷.TarFile.next()— 읽기로 열렸을 때 다음 멤버TarInfo반환, 없으면None.TarFile.extractall(path='.', members=None, *, numeric_owner=False, filter=None)— 모든 멤버를 추출. 디렉터리 정보(소유자, 수정 시간, 권한)는 모든 멤버 추출 후에 설정돼요.numeric_owner=True면 uid/gid 숫자를 사용. 경고: 신뢰하지 않는 소스의 아카이브를 검사 없이 추출하지 마세요. 3.14부터 기본 필터가'data'. 3.5 numeric_owner, 3.6 path-like path, 3.12 filter 추가, 3.14 filter 기본'data'.TarFile.extract(member, path='', set_attrs=True, *, numeric_owner=False, filter=None)— 멤버 하나를 추출.member는 파일 이름 또는TarInfo.set_attrs가 false면 파일 속성(소유자, mtime, mode)을 설정하지 않아요.extract()는 여러 추출 문제를 처리하지 않으니 대부분extractall()을 쓰는 게 좋아요. 3.2 set_attrs, 3.5 numeric_owner, 3.12 filter 추가.TarFile.extractfile(member)— 멤버를 파일 객체로 추출. 일반 파일이나 링크면io.BufferedReader객체, 그 외 기존 멤버는None. 없으면KeyError. 3.3에서io.BufferedReader반환. 3.13에서mode속성이 항상'rb'.TarFile.errorlevel: int—0이면 오류 무시(디버그 출력에만),1(기본)이면 치명적 오류를OSError/FilterError로 발생,2면 비치명적 오류도TarError로 발생.TarFile.extraction_filter—extract()/extractall()의filter인자 기본값.None(기본)이면data필터 사용. 인스턴스나 서브클래스에서 설정 가능. 3.12 추가, 3.14에서 기본data.TarFile.add(name, arcname=None, recursive=True, *, filter=None)— 파일/디렉터리 등을 아카이브에 추가. 디렉터리는 기본 재귀 추가(정렬 순서).filter는TarInfo를 받아 변경/반환,None반환 시 제외. 3.2 filter, 3.7 재귀 정렬 추가.TarFile.addfile(tarinfo, fileobj=None)—TarInfo를 아카이브에 추가. 0이 아닌 크기의 일반 파일이면fileobj(바이너리 파일)에서tarinfo.size바이트를 읽어 추가. 3.13에서 0이 아닌 크기 일반 파일엔 fileobj 필수.TarFile.gettarinfo(name=None, arcname=None, fileobj=None)—os.stat()등의 결과에서TarInfo생성.arcname생략 시fileobj.name/name사용. 3.6 name path-like.TarFile.close()—TarFile닫기. 쓰기 모드에선 마무리 0 블록 두 개를 추가.TarFile.pax_headers: dict— pax 전역 헤더 키-값 딕셔너리.
TarInfo 객체
TarInfo 객체는 TarFile의 한 멤버를 나타내고, 파일의 데이터 자체는 담지 않아요. TarFile의 getmember()/getmembers()/gettarinfo()가 반환해요. 반환된 객체를 수정하면 이후 모든 아카이브 작업에 영향이 가므로, copy.copy()나 replace()로 복사본을 만들어 쓰는 게 좋아요.
class tarfile.TarInfo(name='') — TarInfo 객체 생성.
classmethod TarInfo.frombuf(buf, encoding, errors)— 버퍼buf에서TarInfo생성. 무효면HeaderError.classmethod TarInfo.fromtarfile(tarfile)— 다음 멤버를 읽어TarInfo로 반환.TarInfo.tobuf(format=DEFAULT_FORMAT, encoding=ENCODING, errors='surrogateescape')—TarInfo에서 문자열 버퍼 생성.
공개 데이터 속성:
-
name: str— 멤버 이름.size: int— 바이트 크기.mtime: int | float— 마지막 수정 시간(epoch 초,os.stat_result.st_mtime처럼).mode: int— 권한 비트(os.chmod()처럼).type— 파일 타입(주로REGTYPE,AREGTYPE,LNKTYPE,SYMTYPE,DIRTYPE,FIFOTYPE,CONTTYPE,CHRTYPE,BLKTYPE,GNUTYPE_SPARSE;is*()메서드로 판별).linkname: str—LNKTYPE/SYMTYPE에서만 존재하는 대상 파일 이름(심볼릭 링크는 링크가 있는 디렉터리 기준, 하드링크는 아카이브 루트 기준).uid,gid,uname,gname— 원래 저장한 사용자/그룹 정보.chksum: int— 헤더 체크섬.devmajor,devminor— 장치 번호.offset— tar 헤더 시작.offset_data— 파일 데이터 시작.sparse— 희소 멤버 정보.pax_headers: dict— 관련 pax 확장 헤더. 3.12에서mtime/mode/uid/gid/uname/gname은None으로 설정하면 추출 시 해당 속성을 건너뜀. -
TarInfo.replace(name=..., mtime=..., mode=..., linkname=..., uid=..., gid=..., uname=..., gname=..., deep=True)— 주어진 속성을 바꾼 새 복사본 반환. 기본 깊은 복사,deep=False면 얕은 복사(공유). 3.12 추가.new_tarinfo = old_tarinfo.replace(gname='staff')
질의 메서드: isfile()/isreg()(일반 파일), isdir(), issym()(심볼릭 링크), islnk()(하드 링크), ischr()(문자 장치), isblk()(블록 장치), isfifo()(FIFO), isdev()(문자/블록/FIFO 중 하나).
추출 필터
3.12 추가. tar 형식은 UNIX 계열 파일시스템의 세부사항을 모두 담도록 설계되어 강력하지만, 추출 시 의도치 않은(어쩌면 악성) 효과를 만드는 tar 파일을 만들기 쉽죠(절대 경로, .. 경로 요소, 심볼릭 링크로 임의 파일 덮어쓰기 등). extract()/extractall()의 filter 인자는:
'fully_trusted'— 모든 메타데이터를 그대로 반영. 아카이브를 완전히 신뢰할 때.'tar'— 대부분의 tar 특유 기능을 허용하되 놀랍거나 악성일 가능성이 큰 기능 차단.'data'— UNIX 계열 기능 대부분 무시/차단. 크로스 플랫폼 데이터 아카이브 추출용.None(기본) —TarFile.extraction_filter사용. 그것도None이면'data'필터.- 콜러블 — 각 멤버마다 호출:
filter(member: TarInfo, path: str, /) -> TarInfo | None.TarInfo를 반환하면 그 메타데이터를 사용,None반환 시 건너뜀, 예외 발생 시errorlevel에 따라 중단/건너뜀.
경고: 어떤 필터도 모든 위험한 기능을 막지 못해요. 신뢰하지 않는 소스의 아카이브를 검사 없이 추출하지 마세요. (참고: PEP 706)
기본 이름 필터:
tarfile.fully_trusted_filter(member, path)—member를 그대로 반환.'fully_trusted'구현.tarfile.tar_filter(member, path)—'tar'필터. 파일 이름의 선행 슬래시 제거, 절대 경로 거부(AbsolutePathError),..요소 정규화(os.path.normpath()), 심볼릭 링크를 따라 절대 경로가 목적지 밖이면 거부(OutsideDestinationError), 높은 모드 비트(setuid/setgid/sticky)와 그룹/기타 쓰기 비트 제거.tarfile.data_filter(member, path)—'data'필터.tar_filter에 더해 링크 대상 정규화, 절대 경로/목적지 밖 링크 거부(AbsoluteLinkError/LinkOutsideDestinationError), 장치 파일(파이프 포함) 거부(SpecialFileError), 일반 파일엔 소유자 읽기/쓰기 권한 설정,uid/gid/uname/gname을None으로 설정.
필터 오류: 필터가 파일 추출을 거부하면 FilterError 서브클래스를 발생시켜요. errorlevel이 1 이상이면 추출 중단, 0이면 로그만 남기고 건너뛰며 계속.
추가 검증 힌트: filter='data'여도 신뢰하지 않는 파일은 검사 없이 추출하기에 부적합해요(서비스 거부 공격 방지는 못해요). 다음과 같은 확인을 고려하세요: 새 임시 디렉터리로 추출, 필요 없으면 심볼릭 링크 금지, 외부(OS 수준) 디스크/메모리/CPU 제한, 파일 이름을 허용 문자 목록과 대조, 예상 확장자 확인, 추출 파일 수/총 크기/파일 이름 길이 제한, 대소문자 구분 없는 파일시스템에서 가려지는 파일 확인. 또한 tar 파일은 같은 파일의 여러 버전을 담을 수 있고(나중 것이 앞을 덮어씀), tarfile은 진행 중 "살아 있는" 데이터 문제를 보호하지 않아요.
구형 Python 지원: hasattr(tarfile, 'data_filter')로 기능 존재를 확인하세요.
my_tarfile.extraction_filter = (lambda member, path: member) # fully trusted
my_tarfile.extractall()
my_tarfile.extraction_filter = getattr(tarfile, 'data_filter',
(lambda member, path: member))
my_tarfile.extractall()
my_tarfile.extractall(filter=tarfile.data_filter)
if hasattr(tarfile, 'data_filter'):
my_tarfile.extractall(filter='data')
else:
my_tarfile.extractall()
상태 유지 필터 예제:
class StatefulFilter:
def __init__(self):
self.file_count = 0
def __enter__(self):
return self
def __call__(self, member, path):
self.file_count += 1
return member
def __exit__(self, *exc_info):
print(f'{self.file_count} files extracted')
with StatefulFilter() as filter_func:
tar.extractall(path, filter=filter_func)
명령줄 인터페이스
3.4 추가. tarfile 모듈은 간단한 CLI를 제공해요.
$ python -m tarfile -c monty.tar spam.txt eggs.txt
$ python -m tarfile -c monty.tar life-of-brian_1979/
$ python -m tarfile -e monty.tar
$ python -m tarfile -e monty.tar other-dir/
$ python -m tarfile -l monty.tar
옵션: -l <tarfile>/--list(파일 목록), -c <tarfile> <source1> ... <sourceN>/--create(생성), -e <tarfile> [<output_dir>]/--extract(추출), -t <tarfile>/--test(유효성 검사), -v/--verbose, --filter <filtername>(fully_trusted/tar/data).
예제
읽기:
import tarfile
tar = tarfile.open("sample.tar.gz")
tar.extractall(filter='data')
tar.close()
import os
import tarfile
def py_files(members):
for tarinfo in members:
if os.path.splitext(tarinfo.name)[1] == ".py":
yield tarinfo
tar = tarfile.open("sample.tar.gz")
tar.extractall(members=py_files(tar))
tar.close()
import tarfile
tar = tarfile.open("sample.tar.gz", "r:gz")
for tarinfo in tar:
print(tarinfo.name, "is", tarinfo.size, "bytes in size and is ", end="")
if tarinfo.isreg():
print("a regular file.")
elif tarinfo.isdir():
print("a directory.")
else:
print("something else.")
tar.close()
쓰기:
import tarfile
tar = tarfile.open("sample.tar", "w")
for name in ["foo", "bar", "quux"]:
tar.add(name)
tar.close()
import tarfile
with tarfile.open("sample.tar", "w") as tar:
for name in ["foo", "bar", "quux"]:
tar.add(name)
import sys
import tarfile
with tarfile.open("sample.tar.gz", "w|gz", fileobj=sys.stdout.buffer) as tar:
for name in ["foo", "bar", "quux"]:
tar.add(name)
import tarfile
def reset(tarinfo):
tarinfo.uid = tarinfo.gid = 0
tarinfo.uname = tarinfo.gname = "root"
return tarinfo
tar = tarfile.open("sample.tar.gz", "w:gz")
tar.add("foo", filter=reset)
tar.close()
지원되는 tar 형식
- POSIX.1-1988 ustar(
USTAR_FORMAT) — 파일 이름 최대 256자, 링크 이름 100자, 최대 8 GiB. 오래되고 제한적이지만 널리 지원. - GNU tar(
GNU_FORMAT) — 긴 파일/링크 이름, 8 GiB 초과 파일, 희소 파일. GNU/Linux의 사실상 표준. 긴 이름 확장은 완전 지원, 희소 파일은 읽기 전용. - POSIX.1-2001 pax(
PAX_FORMAT) — 사실상 제한 없는 가장 유연한 형식. 현재 기본. 기존 ustar를 확장 헤더로 확장(확장 헤더는 뒤 파일에만, 전역 헤더는 전체에 영향). 데이터는 UTF-8로 인코딩.
읽기만 가능한 형식: 고대 V7 형식(일반 파일/디렉터리만, 이름 100자 제한, 사용자/그룹 이름 없음), SunOS tar 확장 형식(PAX 변형이지만 호환 안 됨).
유니코드 문제
원래 tar 형식은 서로 다른 문자 인코딩 개념이 없어서, UTF-8 시스템에서 만든 아카이브가 비 ASCII 문자를 담으면 Latin-1 시스템에서 제대로 읽히지 못해요. 인코딩 자동 감지 방법은 없고, pax 형식이 UTF-8로 비 ASCII 메타데이터를 저장해 해결해요. 변환 세부사항은 TarFile의 encoding/errors 인자가 제어해요. encoding 기본값은 sys.getfilesystemencoding()(또는 'ascii'), errors 기본값은 'surrogateescape'예요. PAX_FORMAT에선 메타데이터가 UTF-8이라 일반적으로 encoding이 필요 없어요.
더 알아보기
zipfile— 표준zipfile모듈 문서.shutil— 고수준 아카이빙 작업(shutil.make_archive()등).- GNU tar 매뉴얼의 Basic Tar Format — tar 아카이브 형식과 GNU tar 확장 문서.
- PEP 706 — 추출 필터 설계 배경.