본문 바로가기
PYTHON(파이썬)/파이썬 활용

특정 디렉터리에서 변경된 파일을 나스(NAS)에 FTP 프로토콜을 통해 복사(업로드)하는 프로그램

by eplus 2024. 11. 15.
###################################################
# 파일을 나스에 복사 - FTP
#   Date : 2023-08-10  By : EPLUS
#    1. 폴드에서 변경된 일자 기준으로
#    2. NAS에 접속 후 Upload (FTP)
###################################################
import ftplib
import os, sys, time, shutil
from datetime import datetime, timedelta
#######################################################
def upload_file(path, filename):
    os.chdir(path)
    myfile = open(filename,'rb')
    ftp.storbinary('STOR '+ filename, myfile)
    myfile.close()
    #
    print("upload_file: ", path, filename)
    #
#    
def CopyFile(directory, fromFile, toFile):
    try:
        if not os.path.exists(directory):
            os.makedirs(directory)
        shutil.copyfile(fromFile, toFile)
    except OSError:
        print("Error: Failed to create the directory.")
#######################################################    
sfrom = "c:/epython"  # c:/ or e:/  폴드가 있으면 e:/ework
sto = "./g/cbackup"  # FTP 폴드 대/소문자 구분함

if len(sys.argv) == 3:
    sfrom = sys.argv[1]
    sto = sys.argv[2]
#
ftp = ftplib.FTP()
ftp.set_debuglevel(0)
ftp.encoding = 'cp949'  # 한글 폴드 또는 파일 처리 시 utf-8 대신 사용
ftp.connect("t.e.co.kr", 231)
ftp.login("ftpA","A123~")
#
now = datetime.now()
snow = now.strftime('%Y-%m-%d %H:%M:%S')
print("Backup Start : ", snow, sfrom, sto)
#
now = datetime.now()
snow = now.strftime('%Y-%m-%d')
now = now - timedelta(days=1)
snow0 = now.strftime('%Y-%m-%d')
#
iFcnt = 0
#######################################################
# pC에서 일단위로 ftp에 저장 - 대상 파일 및 폴드 지정
#######################################################
if sfrom != '':
    smypath = sfrom
if sto != '':
    smyftp = sto
#######################################################
sdir = smyftp + "/" + snow
ftp.cwd(smyftp)
#
try:
    if snow not in ftp.nlst():
        ftp.mkd(snow)
except:
    print("### 폴드생성 오류 1 ###_DIR: ", snow)

ftp.cwd(snow)
#
print("1:_" + smyftp, snow)    
#######################################################
for (path, dir, files) in os.walk(smypath):
    for filename in files:
        sdate = datetime.fromtimestamp(os.path.getmtime(path + str("/")+ filename)).strftime('%Y-%m-%d')
        stime = datetime.fromtimestamp(os.path.getmtime(path + str("/")+ filename)).strftime('%H:%M:%S')
        #
        if sdate == snow or sdate == snow0:  # 당일 또는 전일에 수정 또는 생성된 파일
            iFcnt = iFcnt + 1
            #print(path + str("/")+ filename, stime)
            #
            sdir2 = path
            sdir2 = sdir2.replace(chr(92), '/')
            sdir2 = sdir2.replace('/', '_')
            sfdir = sdir+"/"+sdir2
            #--------------------------------------------------
            #try:
            #    if sdir2 not in ftp.nlst():
            #        print("3.1:_" + sfdir)
            ##        ftp.mkd(sdir2)
            #except Exception as err:
            #    print("### 폴드생성 오류 2###_DIR: " , err)
            #-------------------------------------------------
            if len(sdir2) > 100:
                sdir2 = sdir2[:90] + 'XXXX'
            try:
                ftp.cwd(sdir2)
            except:
                if ftp.pwd() != sdir2:
                    ftp.mkd(sdir2)                
                    ftp.cwd(sdir2)
            #
            print("4:_" + sdir2 + ' : ' + str(iFcnt))
            #
            try:
                upload_file(path, filename)
            except Exception as err:
                print("### Upload 오류 ###_FiLE: ", filename, err)
                # 오류발생시 파일 복사
                spath = "e:/back_file/" + snow
                fromFile = path + '/' + filename
                toFile = spath + '/' + filename
                CopyFile(spath, fromFile, toFile)                
                #
                time.sleep(1)
            #                
            try:
                ftp.cwd("..")                
            except:
                print("### 폴드이동 오류 ###_path: ", path)
                time.sleep(1)
                ftp.cwd("..")
            time.sleep(0.1)
########################################################
ftp.close
########################################################
now = datetime.now()
snow = now.strftime('%Y-%m-%d %H:%M:%S')
print("Backup 완료 : ", snow, smypath, smyftp)
#######################################################

NAS FTP 접속 정보는 임의로 변경했음...개발자의 NAS 접속 정보에 맞게 수정 가능후 사용가능....

이 코드는 특정 디렉터리에서 변경된 파일을 나스(NAS)에 FTP 프로토콜을 통해 복사(업로드)하는 프로그램입니다. 주석과 코드를 통해 기능을 단계적으로 설명하겠습니다.

### 주요 목적 및 흐름
1. **지정된 폴더의 변경된 파일을 찾는다.**
2. **FTP 서버에 접속하여 NAS에 업로드한다.**
3. **업로드에 실패한 파일은 로컬 백업 디렉터리에 복사한다.**

### 주요 구성 요소
1. **라이브러리 임포트**
   ```python
   import ftplib
   import os, sys, time, shutil
   from datetime import datetime, timedelta
   ```
   - `ftplib`: FTP 기능을 사용하기 위해 필요합니다.
   - `os`, `sys`, `time`, `shutil`: 파일 및 폴더를 다루고, 시간을 조정하며 시스템 작업을 처리하는 라이브러리입니다.
   - `datetime`, `timedelta`: 날짜와 시간을 다루는 데 사용됩니다.

2. **FTP 파일 업로드 함수**
   ```python
   def upload_file(path, filename):
       os.chdir(path)
       myfile = open(filename, 'rb')
       ftp.storbinary('STOR ' + filename, myfile)
       myfile.close()
       print("upload_file: ", path, filename)
   ```
   - FTP를 통해 파일을 업로드하는 함수입니다.
   - 파일을 바이너리 모드로 읽고, FTP 서버에 업로드합니다.

3. **로컬 파일 복사 함수**
   ```python
   def CopyFile(directory, fromFile, toFile):
       try:
           if not os.path.exists(directory):
               os.makedirs(directory)
           shutil.copyfile(fromFile, toFile)
       except OSError:
           print("Error: Failed to create the directory.")
   ```
   - 파일 복사 중 에러가 발생할 경우 디렉토리를 생성하고 복사합니다.

4. **FTP 접속 설정 및 기본 경로 설정**
   ```python
   ftp = ftplib.FTP()
   ftp.set_debuglevel(0)
   ftp.encoding = 'cp949'  # 한글 폴드 또는 파일 처리 시 utf-8 대신 사용
   ftp.connect("t.e.co.kr", 231)
   ftp.login("ftpA", "A123~")
   ```
   - `cp949` 인코딩은 한글 파일명 처리를 위해 사용됩니다.
   - FTP 서버에 접속 후 로그인을 시도합니다.

5. **백업 시작 시점과 전날 날짜 설정**
   ```python
   now = datetime.now()
   snow = now.strftime('%Y-%m-%d')
   now = now - timedelta(days=1)
   snow0 = now.strftime('%Y-%m-%d')
   ```
   - 백업 작업의 현재 시간 및 전날 날짜를 설정합니다.
   - 당일과 전일 파일을 구분하여 업로드합니다.

6. **FTP 폴더 생성 및 파일 업로드**
   ```python
   sdir = smyftp + "/" + snow
   ftp.cwd(smyftp)
   try:
       if snow not in ftp.nlst():
           ftp.mkd(snow)
   except:
       print("### 폴드생성 오류 1 ###_DIR: ", snow)
   ```
   - 지정된 NAS의 폴더로 이동한 후, 당일 날짜 폴더가 없으면 생성합니다.
   - FTP 서버에서 현재 폴더 목록을 확인하고, 날짜 폴더가 없으면 새로 생성하는 방식입니다.

7. **디렉터리 순회 및 파일 조건에 따른 업로드**
   ```python
   for (path, dir, files) in os.walk(smypath):
       for filename in files:
           sdate = datetime.fromtimestamp(os.path.getmtime(path + str("/") + filename)).strftime('%Y-%m-%d')
           ...
           if sdate == snow or sdate == snow0:
               ...
               try:
                   upload_file(path, filename)
               except Exception as err:
                   ...
                   CopyFile(spath, fromFile, toFile)
   ```
   - 지정된 폴더(`smyftp`)를 순회하면서 파일의 최종 수정 날짜를 확인합니다.
   - 당일(`snow`) 또는 전일(`snow0`)에 수정된 파일만 업로드 대상으로 간주합니다.
   - 업로드 실패 시 `CopyFile` 함수를 호출해 로컬 백업 디렉터리에 복사합니다.

8. **마무리 및 종료 로그**
   ```python
   ftp.close()
   now = datetime.now()
   snow = now.strftime('%Y-%m-%d %H:%M:%S')
   print("Backup 완료 : ", snow, smypath, smyftp)
   ```
   - 모든 작업이 완료되면 FTP 연결을 종료하고 작업 완료 시간을 출력합니다.

### 주요 기능 요약
1. **파일 탐색 및 수정 시간 확인**: `os.walk()`와 `os.path.getmtime()`을 사용해 지정된 폴더 내 모든 파일을 탐색하며, 특정 시간 기준으로 필터링합니다.
2. **FTP 서버 접속 및 폴더 생성**: NAS에 해당하는 FTP 서버에 접속하고, 필요하면 날짜별 폴더를 생성합니다.
3. **파일 업로드**: 수정된 파일을 FTP 서버에 업로드합니다.
4. **에러 처리**: 업로드 실패 시 파일을 로컬 백업 디렉터리에 복사합니다.

이 프로그램은 일정 폴더의 파일을 기준으로 NAS에 백업하는 목적으로 설계되었으며, 사용자는 경로를 변경하거나 FTP 설정을 조정하여 다양한 백업 상황에 대응할 수 있습니다.

728x90
반응형