본문 바로가기
SW 개발/Python

Python: 폴더 백업 기능 구현 (7zip 압축, Sample code)

by Kibua20 2020. 7. 9.

특정 폴더(working_folder)를 일정 시간 간격으로 백업을 해야 기능이 필요해서 python으로 구현한 내용을 공유합니다.  특정 폴더의 백업 기능의 상세 구현 사항은 아래와 같습니다. 

 

  • Working folder의 하위에 모든 파일을 backup 한다.  (주기적으로 실행은 crontab 사용)
  • 하드 디스크를 용량을 절약하기 위해서 7zip 파일로 압축한다. (압축 포맷은 효율이 좋은 7 zip 사용)
  • 백업 폴더에서 백업 파일 7zip 파일의 개수는 미리 설정한 최대 개수를 초과하지 않는다. 
  • 백업 파일의 최대 개수가 초과하는 경우 오래된 파일부터 삭제한다.
  • 7zip 파일은 비밀 번호 설정한다.  

아래 코드는 우분투를 환경에서 동작하는 검증한 code이고, os.system()를 수정하면 windows에서도 동작 가능합니다. 만일 cygwin이 설치된 상태라면  p7zip-full을 설치하고 $PATH를 설정해야 하고, WSL(Windows Substem for Linux)에서도 p7zip-full 패키지를 설치하면 동작 가능합니다. 

폴더 백업 기능 구현: 7zip으로 주기적으로 압축하고 백업 시점을 기록

 

구현 방법

Python으로 구현한 code는 아래와 같습니다.  main() 함수에서는 Working folder와 Backup folder를 path을 입력받고, backup() 함수를 호출합니다. backup() 함수에서는 7zip을 os.system() 함수를 통해서 command line으로 호출하고,  Working 폴더를 압축합니다. 압축한 폴더에서 7zip 파일을 개수를 확인해서 최대 개수가 넘어가는 경우 오래된 파일부터 삭제하도록 구현합니다.

 

7zip으로 압축하는 것은 Python으로 구현할 필요는 없고, os.system() 명령어나 os.subprocess()를 통해서 bash로 command line 명령어를 실행합니다.  우분투 환경에서 7zip을 지원하는 7za 명령어를 사용할 수 있으며, 윈도우에서는 우분투와 동일한 명령어 옵션으로 7z.exe를 사용할 수 있습니다.

 

사전 작업

우분투에서 $ sudo apt install  p7zip-full 설치해야 합니다. 윈도우에서는 7z.exe 를 다운로드 받아서 PATH를 설정합니다.

 

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import sys
import os
import time

# 7za install
# sudo apt install p7zip-full
#
# $ 7za a  -pmy_password archive.7z a_directory
# $ 7za a -p0000 test_dir.7zip ./temp/
# $ 7za x -p0000 -y test_dir.7zip
# $ za x -p0000 -y -O./backup test_dir.7zip
# $ 7za a -p0000 -y -O./backup_dir test_dir.7zip
# On Linux/Unix, in order to backup directories you must use tar :
# - to backup a directory  : tar cf - directory | 7za a -si -y directory.tar.7z
# - to restore your backup : 7za x -so directory.tar.7z | tar xf -

def backup(archive_dir, backup_dir, password=True, max_files=10):
    curdate = time.strftime('%Y%m%d-%H%M%S', time.localtime(time.time()))

    dirName = os.path.basename(archive_dir)
    if (dirName == ""):
        dirName = os.path.basename(os.path.dirname(archive_dir))
    
    zipfile = os.path.join(backup_dir, dirName +'_'+ curdate+'.7z')

    passwd =''
    if password == True:
        passwd += '-p' + '0000' + ' '

    cmd = '7za a -y -bso0 '
    cmd +=  passwd + ' '
    cmd +=  zipfile + ' '
    cmd +=  archive_dir + ' '
    # print (cmd)

    os.system(cmd)

    if os.path.exists(backup_dir):
        backuplist = [f for f in os.listdir(backup_dir) if f.endswith('.7z')]
        backuplist.sort()

        while ( len(backuplist) > max_files):
            cmd = 'rm ' + os.path.join (backup_dir, backuplist[0])
            os.system(cmd)
            del backuplist[0]

def main():
    archive_dir = os.path.join (os.getcwd(), 'working_dir')
    backup_dir = os.path.join (os.getcwd(), 'test_dir')

    for i in range(1, len(sys.argv)):
        if (i == 1):
            archive_dir = sys.argv[1]
        elif (i == 2):
            backup_dir = sys.argv[2]
        else:
            print('*** Error *** : Unknown parametMGer')
            exit(1)

    if (len(sys.argv) < 2):
        print('Usage: ./zipper.py [archive_dir] [backup_dir]')
        exit(-1)

    backup (archive_dir, backup_dir, password=True)

if __name__ == "__main__":
    main()

 

backup() 함수 설명

backup()는 Working 폴더와 백업 폴더의 path를 전달받아서 현재 시간과 조합하여 백업 파일의 이름을 생성합니다.  그다음 7za로 7zip 포맷으로 압축하고, 백업 폴더의 압축 파일을 저장합니다.  백업 폴더 안에 *.7zip 파일 개수를 확인하고 오래된 파일부터 삭제하도록 구현하였습니다.  각 라인별 세부 설명은 아래와 같습니다.

 

# local time을 얻어 스트링으로 변환한다. 날짜-시간 포맷으로 표시한다.  

curdate = time.strftime('%Y%m%d-%H%M%S', time.localtime(time.time()))

 

# working 폴더의 이름을 받아온다.  ./working_folder/ 인 경우 os.path.basename()은 null string을 리턴하기 때문에 os.path.dirname()으로 한 번 더 체크한다.  

dirName = os.path.basename(archive_dir)

if (dirName == ""):

    dirName = os.path.basename(os.path.dirname(archive_dir))

 

# 압축 파일 이름을 폴더이름+날짜_시간.7zip 포맷으로 한다.

zipfile = os.path.join(backup_dir, dirName +'_'+ curdate+'.7z')

 

# 패스워드는 -p'password' 의 parmater로 전달해야 한다. 아래 예제는 password를 '1234'로 설정한 경우이다.

passwd += '-p' + '1234'  + ' '

 

# 7za a -y -bso0 -p'1234'  zipfilename ./working_folder 를 실행한다. 

cmd = '7za a -y -bso0 '     # 7za로 압축한다.   -y는 질문의 있는 경우 모두  yes 답한다. -bsoO는 7za의 표준 출력을 disable

cmd += passwd + ' '          # password 설정

cmd += zipfile + ' '

cmd += archive_dir + ' '

 

# bash cmd로 7zip 으로 압축

os.system(cmd)

 

#확장자가 *.7z 파일 list를 받아오고, 오래된 파일 이름 기준으로 정렬한다.

backuplist = [f for f in os.listdir(backup_dir) if f.endswith('.7z')]

backuplist.sort()

 

# backup 폴더의 파일 개수를 확인하고 최대 개수만 남기고 오래된 파일은 삭제한다. 

while ( len(backuplist) > max_files):

    cmd = 'rm ' + os.path.join (backup_dir, backuplist[0])     # rm oldbackup_file 실행

    os.system(cmd)

    del backuplist[0]

 

관련글

[개발환경] - 우분투 작업 스케줄러 Crontab 사용법, 디버깅, 주의 사항

[개발환경] - 우분투에서 7zip 사용하기 (p7zip과 7za추천)

[모바일/REST API] - Google Gmail API 사용 방법 (1) - Sample code

[모바일/Python] - Python 에러: /usr/bin/env: `python3\r': 그런 파일이나 디렉터리가 없습니다

[모바일/Python] - Python 표준 입출력(stdin/stdout) 활용 - 리눅스 프로그램과 연동

[모바일/Python] - Python JSON 사용 시 TypeError: Object of type bytes is not JSON serializable

[모바일/Python] - Python smtplib 사용한 email 발송 예제 (gmail)

[모바일/Python] - Python SyntaxError: Non-ASCII character in file on, but no encoding declared

[모바일/Python] - Python 2.7과 3.8호환성: a bytes-like object is required, not 'str'에러 수정

[모바일/Python] - [Tips] Python: XML Parsing 시 multiple elements on top level

[모바일/Python] - [Tips] Python 에서 XML comment 처리 - Sample code 제공

[모바일/Python] - [Tips] XML 에서 예약/특수 문자 처리

  

 

 




댓글