문제 상황
파이썬으로 여러 개의 파일을 하나의 ZIP 아카이브로 압축하고 싶습니다.
개요
ZIP 파일은 여러 개의 파일 내용을 압축하여 하나의 아카이브에 담을 수 있는 형식입니다. 파일을 압축하면 디스크 용량을 절약할 수 있으며, 인터넷을 통해 전송하거나 Control-M AFT, Connect:Direct, scp 등을 이용해 시스템 간에 파일을 주고받을 때 특히 유용합니다.
파이썬 프로그램은 표준 라이브러리인 zipfile 모듈의 함수들을 사용하여 ZIP 파일을 손쉽게 생성할 수 있습니다.
구현 방법
1단계: 필요한 패키지 준비
이 예제에서는 zipfile, io, pandas 패키지를 사용합니다. 시스템에 패키지가 없다면 pip로 설치하세요. 설치 여부가 확실하지 않다면 pip freeze 명령어로 확인할 수 있습니다.
2단계: 데이터를 파일로 저장하는 함수 작성
먼저 문자열 데이터를 CSV 파일로 저장하는 함수를 작성합니다. 아래의 write_data_to_files 함수는 데이터와 파일명을 입력받아 현재 디렉터리에 해당 이름의 파일을 생성합니다.
# 함수 : write_data_to_files
def write_data_to_files(inp_data, file_name):
"""
function : 전달받은 데이터로 csv 파일 생성
args : inp_data : 대상 파일에 기록할 데이터
file_name : 데이터를 저장할 대상 파일명
return : none
assumption : 생성될 파일과 이 코드가 같은 디렉터리에 있음.
"""
print(f" *** Writing the data to - {file_name}")
throwaway_storage = io.StringIO(inp_data)
with open(file_name, 'w') as f:
for line in throwaway_storage:
f.write(line)3단계: 파일을 ZIP으로 압축하는 함수 작성
이제 위 단계에서 생성한 파일들을 ZIP으로 묶는 file_compress 함수를 작성합니다. 이 함수는 파일명 리스트를 입력받아 각 파일을 순회하며 하나의 ZIP 파일로 압축합니다. 각 단계에 대한 자세한 설명은 코드의 주석에 포함되어 있습니다.
직접 압축된 ZIP 파일을 만들려면 ZipFile 객체를 쓰기(write) 모드로 열어야 합니다. 즉, 두 번째 인자로 'w'를 전달하면 됩니다.
write() 메서드의 첫 번째 인자: ZIP 파일에 추가할 파일명(경로) 문자열입니다. 경로를 전달하면 파이썬은 해당 경로의 파일을 압축하여 ZIP 파일에 추가합니다.
두 번째 인자: 압축 방식(compression type) 매개변수로, 컴퓨터가 어떤 알고리즘으로 파일을 압축할지 지정합니다.
# 함수 : file_compress
def file_compress(inp_file_names, out_zip_file):
"""
function : file_compress
args : inp_file_names : zip으로 묶을 파일명 리스트
out_zip_file : 출력 zip 파일명
return : none
assumption : 입력 파일 경로와 이 코드가 같은 디렉터리에 있음.
"""
# 압축 시에는 ZIP_DEFLATED 모드 선택
# 또는 zipfile.ZIP_STORED를 사용하면 압축 없이 저장만 함
compression = zipfile.ZIP_DEFLATED
print(f" *** Input File name passed for zipping - {inp_file_names}")
# zip 파일 생성 - 첫 번째 매개변수: 경로/파일명, 두 번째: 모드
print(f' *** out_zip_file is - {out_zip_file}')
zf = zipfile.ZipFile(out_zip_file, mode="w")
try:
for file_to_write in inp_file_names:
# zip 파일에 파일 추가
# 첫 번째 매개변수: 압축할 파일, 두 번째: zip 내부의 파일명
print(f' *** Processing file {file_to_write}')
zf.write(file_to_write, file_to_write, compress_type=compression)
except FileNotFoundError as e:
print(f' *** Exception occurred during zip process - {e}')
finally:
# 파일을 반드시 닫아주세요!
zf.close()4단계: 함수 호출 및 실행
이제 함수들을 호출하여 두 개의 CSV 파일을 생성한 후 하나의 ZIP 파일로 압축해 보겠습니다. 그랜드슬램 타이틀을 2개 이상 획득한 테니스 선수 데이터를 temporary_file1_for_zip.csv에, 1개 이하로 획득한 선수 데이터를 temporary_file2_for_zip.csv에 저장한 뒤, 두 파일을 모두 temporary.zip으로 압축합니다.
import zipfile import io import pandas as pd file_name1 = "temporary_file1_for_zip.csv" file_name2 = "temporary_file2_for_zip.csv" file_name_list = [file_name1, file_name2] zip_file_name = "temporary.zip" # 파일 1에 들어갈 데이터 file_data_1 = """ player,titles Federer,20 Nadal,20 Djokovic,17 Murray,3 """ # 파일 2에 들어갈 데이터 file_data_2 = """ player,titles Thiem,1 Zverev,0 Medvedev,0 Rublev,0 """ # file_data를 file_name에 기록 write_data_to_files(file_data_1, file_name1) write_data_to_files(file_data_2, file_name2) # file_name을 zip_file_name으로 압축 file_compress(file_name_list, zip_file_name)
전체 코드 통합
위에서 설명한 모든 단계를 하나의 완전한 스크립트로 정리하면 다음과 같습니다.
import zipfile
import io
import pandas as pd
# 함수 : write_data_to_files
def write_data_to_files(inp_data, file_name):
"""
function : 전달받은 데이터로 csv 파일 생성
args : inp_data : 대상 파일에 기록할 데이터
file_name : 데이터를 저장할 대상 파일명
return : none
assumption : 생성될 파일과 이 코드가 같은 디렉터리에 있음.
"""
print(f" *** Writing the data to - {file_name}")
throwaway_storage = io.StringIO(inp_data)
with open(file_name, 'w') as f:
for line in throwaway_storage:
f.write(line)
# 함수 : file_compress
def file_compress(inp_file_names, out_zip_file):
"""
function : file_compress
args : inp_file_names : zip으로 묶을 파일명 리스트
out_zip_file : 출력 zip 파일명
return : none
assumption : 입력 파일 경로와 이 코드가 같은 디렉터리에 있음.
"""
compression = zipfile.ZIP_DEFLATED
print(f" *** Input File name passed for zipping - {inp_file_names}")
print(f' *** out_zip_file is - {out_zip_file}')
zf = zipfile.ZipFile(out_zip_file, mode="w")
try:
for file_to_write in inp_file_names:
print(f' *** Processing file {file_to_write}')
zf.write(file_to_write, file_to_write, compress_type=compression)
except FileNotFoundError as e:
print(f' *** Exception occurred during zip process - {e}')
finally:
zf.close()
# __main__ 프로그램
if __name__ == '__main__':
# 파일명과 데이터 정의
file_name1 = "temporary_file1_for_zip.csv"
file_name2 = "temporary_file2_for_zip.csv"
file_name_list = [file_name1, file_name2]
zip_file_name = "temporary.zip"
file_data_1 = """
player,titles
Federer,20
Nadal,20
Djokovic,17
Murray,3
"""
file_data_2 = """
player,titles
Thiem,1
Zverev,0
Medvedev,0
Rublev,0
"""
# file_data를 file_name에 기록
write_data_to_files(file_data_1, file_name1)
write_data_to_files(file_data_2, file_name2)
# file_name을 zip_file_name으로 압축
file_compress(file_name_list, zip_file_name)*** Writing the data to - temporary_file1_for_zip.csv *** Writing the data to - temporary_file2_for_zip.csv *** Input File name passed for zipping - ['temporary_file1_for_zip.csv', 'temporary_file2_for_zip.csv'] *** out_zip_file is - temporary.zip *** Processing file temporary_file1_for_zip.csv *** Processing file temporary_file2_for_zip.csv
실행 결과
위 코드를 실행하면 다음과 같은 결과를 얻을 수 있습니다.
현재 디렉터리에
temporary_file1_for_zip.csv파일이 생성됩니다.현재 디렉터리에
temporary_file2_for_zip.csv파일이 생성됩니다.현재 디렉터리에
temporary.zip파일이 생성됩니다.
마무리
파이썬의 zipfile 모듈을 활용하면 별도의 외부 도구 없이도 순수 파이썬 코드만으로 파일 압축을 자동화할 수 있습니다. 로그 파일 백업, 대용량 데이터 전송 전 사전 압축, 배치 작업 결과물 패키징 등 다양한 실무 시나리오에 응용해 보세요. 참고로 ZIP_DEFLATED 대신 zipfile.ZIP_STORED를 사용하면 압축 없이 파일을 단순히 묶기만 할 수도 있습니다.