python脚本---上传本机文件到远端(接上文)

上一个脚本刚写完,第二天不用了。。。需要传到linux服务器上。。。
So,下一个脚本开始:

1. 这次选择用的paramiko模块

pip install paramiko

2. 整体思路

  • 遍历本地目录放入集合
  • 读取上次上传到linux的文件信息(existsfile.log)放入另一个集合
  • 两个集合取补集(好像叫对称差集吧)
  • 上传补集内的文件

远程目录必须存在,put方法的远程目录才有效。而且必须是文件的绝对路径,不能是文件夹路径,否则也会失败;mkdir方法一样,不可以递归地创建目录,在这两个地方坑了好久。

3. 代码实现

syncfiles.py


# -*- coding: utf-8 -*-
__author__ = "hand"

import os
import paramiko
import settings
import platform
from datetime import datetime


class SyncFiles(object):
    """
    复制本机文件到远端
    """
    def __init__(self):
        self.f = open("existsfile.log", "a+")
        self.remote_host = settings.REMOTE_HOST
        self.remote_port = settings.REMOTE_PORT
        self.remote_user = settings.REMOTE_USER
        self.remote_pwd = settings.REMOTE_PWD
        if settings.REMOTE_PATH[-1] == '/' or settings.REMOTE_PATH[-1] == '\':
            self.remote_path = settings.REMOTE_PATH[0:-1]
        else:
            self.remote_path = settings.REMOTE_PATH
        if settings.LOCAL_PATH[-1] == '/' or settings.LOCAL_PATH[-1] == '\':
            self.local_path = settings.LOCAL_PATH[0:-1]
        else:
            self.local_path = settings.LOCAL_PATH

    def get_upload_files(self):
        """获取待上传的所有文件"""
        local_path_set = set()  # 本地文件
        file_transfered_set =set()  # 已经上传过的文件
        for root, dirs, files in os.walk(self.local_path):
            for file in files:
                local_file = os.path.join(root, file)  # 完整的文件路径:/A/B/C/1.txt

                local_path_set.add(local_file)

        self.f.seek(0,0)  # 将记录文件指针放在文件头,用于读文件

        for line in self.f.readlines():
            file_transfered = line.split("-")[-1].strip()

            file_transfered_set.add(file_transfered)

        ready_upload_set = local_path_set ^ file_transfered_set  # 待上传的文件
        return list(ready_upload_set)

    def record_log(self, path):

        now = datetime.now()
        # if platform.platform().startswith("Windows"):
        # self.f.write(now.strftime('%Y/%M/%d %H:%M:%S %A ') + ' -  ' + path + '\r\n')
        # else:
        self.f.write(now.strftime('%Y/%M/%d %H:%M:%S %A ') + ' -  ' + path + '
')

    def transfile(self):
        """上传文件"""
        try:
            # 实例化Transport
            trans = paramiko.Transport((self.remote_host, 22))
            # 建立连接
            trans.connect(username=self.remote_user, password=self.remote_pwd)
            # 实例化一个sftp对象
            sftp = paramiko.SFTPClient.from_transport(trans)

            ready_upload_list = self.get_upload_files()

            already_dir = []  # 存放远端新建的目录
            if ready_upload_list:

                for local_file_path in ready_upload_list:

                    if platform.platform().startswith("Windows"):

                        file_need = local_file_path.replace(self.local_path, '').replace('\','/')  # 取出本地路径后,需要同步到远端的部分:B/C/1.txt

                    else:
                        file_need = local_file_path.replace(self.local_path, '')
                    remote_file_path = self.remote_path + file_need

                    try:
                        # 上传文件,必须是文件的完整路径,远端的目录必须已经存在
                        sftp.put(localpath=local_file_path, remotepath=remote_file_path)
                        self.record_log(local_file_path)
                    except Exception as e:
                        # 如果目录不存在就创建,但是不支持递归创建

                        dir_need_list = os.path.split(file_need)[0].split("/")  # B、C
                        dir1 = ''
                        print dir_need_list
                        for dir in dir_need_list[1:]:
                            if dir not in already_dir:
                                # 目录存在会报错,所以把新建过的目录存在一个全局列表中
                                if platform.platform().startswith("Windows"):
                                    sftp.mkdir(os.path.join(self.remote_path, dir1, dir).replace('\','/'))
                                else:
                                   sftp.mkdir(os.path.join(self.remote_path, dir1, dir))
                            dir1 = dir
                            already_dir.append(dir)  # 新建过的目录存在一个全局列表中
                            # 再次执行
                        sftp.put(localpath=local_file_path, remotepath=remote_file_path)
                        self.record_log(local_file_path)
        except Exception as e:
            pass
        finally:
            trans.close()

if __name__ == "__main__":
    sf = SyncFiles()
    sf.transfile()

settings.py

# -*- coding: utf-8 -*-
__author__ = "hand"

REMOTE_HOST = 'X.X.X.X'
REMOTE_PORT = 22
REMOTE_USER = '用户名'
REMOTE_PWD = '密码'
REMOTE_PATH = '/storage/zhaoning/ttt'
LOCAL_PATH = '/Users/smallcaff/Desktop/filetest'

4. 参考

看过其他一些人的代码,也拉下来测试过,有的好像在创建远端目录时有问题,不知道跟版本有关系没
这篇博客关于paramiko用法写的很详细,paramiko用法没有看官方教程,参考了这个:python模块之 paramiko

原文地址:https://www.cnblogs.com/SmallCaff/p/10650698.html