importzipfile# ZIP 파일 열기 및 목록 확인withzipfile.ZipFile('archive.zip','r')aszf:# 파일 목록print(zf.namelist())# ['file1.txt', 'folder/file2.txt']# 상세 정보forinfoinzf.infolist():print(f"{info.filename}: {info.file_size} bytes")# 특정 파일 읽기withzipfile.ZipFile('archive.zip','r')aszf:content=zf.read('file1.txt')# bytestext=content.decode('utf-8')print(text)# 파일처럼 열기withzipfile.ZipFile('archive.zip','r')aszf:withzf.open('file1.txt')asf:forlineinf:print(line.decode('utf-8').strip())
importzipfilefrompathlibimportPath# 전체 추출withzipfile.ZipFile('archive.zip','r')aszf:zf.extractall('output_dir')# 특정 파일만 추출withzipfile.ZipFile('archive.zip','r')aszf:zf.extract('file1.txt','output_dir')# 안전한 추출 (경로 순회 공격 방지)defsafe_extract(zip_path:str,extract_dir:str)->None:extract_path=Path(extract_dir).resolve()withzipfile.ZipFile(zip_path,'r')aszf:formemberinzf.namelist():member_path=(extract_path/member).resolve()# 추출 경로가 대상 디렉토리 안에 있는지 확인ifnotstr(member_path).startswith(str(extract_path)):raiseValueError(f"Path traversal detected: {member}")zf.extractall(extract_dir)safe_extract('archive.zip','output_dir')
importzipfilefrompathlibimportPath# 새 ZIP 파일 생성withzipfile.ZipFile('new_archive.zip','w')aszf:# 파일 추가zf.write('file1.txt')# 아카이브 내 경로 지정zf.write('file2.txt',arcname='folder/file2.txt')# 문자열에서 직접 추가zf.writestr('hello.txt','Hello, World!')# 압축 옵션withzipfile.ZipFile('compressed.zip','w',zipfile.ZIP_DEFLATED)aszf:zf.write('large_file.txt')# 압축률 조정 (compresslevel: 0-9)withzipfile.ZipFile('compressed.zip','w',zipfile.ZIP_DEFLATED,compresslevel=9)aszf:zf.write('large_file.txt')
1
2
3
4
5
6
7
8
9
10
11
12
# 디렉토리 전체 압축importzipfilefrompathlibimportPathdefzip_directory(dir_path:str,zip_path:str)->None:withzipfile.ZipFile(zip_path,'w',zipfile.ZIP_DEFLATED)aszf:forfile_pathinPath(dir_path).rglob('*'):iffile_path.is_file():arcname=file_path.relative_to(dir_path)zf.write(file_path,arcname)zip_directory('my_folder','my_folder.zip')
zipfile - 기존 ZIP에 추가
1
2
3
4
5
importzipfile# 기존 ZIP에 파일 추가withzipfile.ZipFile('archive.zip','a')aszf:zf.write('new_file.txt')
importtarfile# TAR 파일 열기 (자동 압축 감지)withtarfile.open('archive.tar.gz','r:*')astf:# 파일 목록print(tf.getnames())# 상세 정보formemberintf.getmembers():print(f"{member.name}: {member.size} bytes")# 전체 추출withtarfile.open('archive.tar.gz','r:gz')astf:tf.extractall('output_dir')# 특정 파일만 추출withtarfile.open('archive.tar.gz','r:gz')astf:tf.extract('file1.txt','output_dir')# 안전한 추출 (Py3.12+)withtarfile.open('archive.tar.gz','r:gz')astf:tf.extractall('output_dir',filter='data')# 안전한 필터# Py3.11 이하 안전 추출defsafe_tar_extract(tar_path:str,extract_dir:str)->None:frompathlibimportPathextract_path=Path(extract_dir).resolve()withtarfile.open(tar_path,'r:*')astf:formemberintf.getmembers():member_path=(extract_path/member.name).resolve()ifnotstr(member_path).startswith(str(extract_path)):raiseValueError(f"Path traversal: {member.name}")ifmember.issym()ormember.islnk():raiseValueError(f"Symlink not allowed: {member.name}")tf.extractall(extract_dir)
# 특정 파일 제외importtarfiledefexclude_filter(tarinfo):# .pyc 파일과 __pycache__ 제외iftarinfo.name.endswith('.pyc')or'__pycache__'intarinfo.name:returnNonereturntarinfowithtarfile.open('archive.tar.gz','w:gz')astf:tf.add('my_project',filter=exclude_filter)
메모리 내 처리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
importzipfileimportio# 메모리에서 ZIP 생성buffer=io.BytesIO()withzipfile.ZipFile(buffer,'w',zipfile.ZIP_DEFLATED)aszf:zf.writestr('hello.txt','Hello from memory!')# buffer.getvalue()로 bytes 얻기zip_bytes=buffer.getvalue()# 메모리에서 ZIP 읽기buffer=io.BytesIO(zip_bytes)withzipfile.ZipFile(buffer,'r')aszf:print(zf.read('hello.txt').decode())
자주 하는 실수/주의점
경로 순회 공격: ../../../etc/passwd 같은 악의적 경로 → 추출 전 검증 필수