上一个脚本刚写完,第二天不用了。。。需要传到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