Python实现win10环境下FTP的上传与下载
前言
由于项目需要,需要在本机上模拟FTP的上传与下载,故最近着手在Win10下搭建FTP服务器,接下来就是用代码实现FTP的上传和下载功能
导入需要的库
import os # 本地目录操作
from ftplib import FTP # 远程FTP服务器操作
from time import strftime # 导入这个库是为了获取当前日期,用于目录的命名
连接到FTP服务器
def ftp_connect(ip_addr, port, username, password):
"""
参数:
ip_addr:ip地址
port:端口号
username:用户名
password:密码
"""
ftp = FTP()
try:
print("正在连接 %s" % ip_addr)
ftp.connect(ip_addr, port) # 连接FTP服务器
print("成功连接 %s" % ip_addr)
print("正在登录...")
ftp.login(username, password) # 登录
print("登录成功")
return ftp
except Exception as e:
print("%s", e)
return "" # 连接失败,返回""
判断本地文件与远程文件大小是否相等
def is_same_size(ftp, local_file, remote_file):
"""
参数:
ftp:FTP()创建的对象
local_file:本地文件
remote_file:远程文件
"""
# 获取远程文件的大小
try:
remote_file_size = ftp.size(remote_file)
print("remote_file_size: " + str(remote_file_size))
except Exception as e:
print("%s" % e)
remote_file_size = -1
# 获取本地文件的大小
try:
local_file_size = os.path.getsize(local_file)
print("local_file_size: " + str(local_file_size))
except Exception as e:
print("%s" % e)
local_file_size = -2
# 比较文件大小,大小相等返回True,否则返回False
if remote_file_size == local_file_size:
result = True
else:
result = False
return result
上传到FTP服务器
上传单个文件
def upload_file(ftp, local_file, remote_file):
"""
参数:
ftp:FTP()创建的对象
local_file:本地文件
remote_file:远程文件
"""
if not os.path.isfile(local_file): # 判断本地文件是否存在
print('%s 不存在' % local_file)
return
buf_size = 10240 # 设置缓冲区大小
file_handler = open(local_file, 'rb')
ftp.storbinary('STOR %s' % remote_file, file_handler, buf_size)
file_handler.close()
# 判断文件大小是否相等,不相等则重新上传
if is_same_size(ftp, local_file, remote_file):
print('上传 %s' % local_file + " 成功!")
else:
upload_file(ftp, local_file, remote_file)
上传目录下的文件(递归目录)
def upload_dir(ftp, local_path, remote_path):
"""
参数:
ftp:FTP()创建的对象
local_path:本地目录
remote_path:远程目录
"""
# 打开远程目录,目录不存在则创建
try:
ftp.cwd(remote_path)
except Exception:
ftp.mkd(remote_path)
ftp.cwd(remote_path) # 目录创建后切换到远程目录下
# 切换到本地目录,在FTP递归创建目录和上传文件
try:
os.chdir(local_path) # 切换到本地目录
file_list = os.listdir(os.getcwd()) # 获取文件列表
for file_name in file_list:
# 判断列表中各项是文件还是目录
if not os.path.isdir(file_name): # 若是文件,直接上传
upload_file(ftp, file_name, file_name)
else: # 若是目录,在远程创建目录,递归上传
upload_dir(ftp, file_name, file_name)
# 上传后切换到上一级目录
os.chdir("..")
ftp.cwd("..")
except Exception as e:
print("Error: " + str(e))
从FTP服务器下载
下载单个文件
def download_file(ftp, local_file, remote_file):
"""
参数:
ftp:FTP()创建的对象
local_file:本地文件
remote_file:远程文件
"""
# 判断远端文件是否存在
if remote_file in ftp.nlst():
pass
else:
print(remote_file + "不存在") # 若远端文件不存在则打印错误信息
return
buf_size = 10240
# 判断本地文件是否存在
if not os.path.exists(local_file):
with open(local_file, 'wb') as f:
print("正在下载:" + remote_file)
ftp.retrbinary('RETR %s' % remote_file, f.write, buf_size)
# 判断文件大小是否相等,不相等则重新下载
if is_same_size(ftp, local_file, remote_file):
print("%s 下载成功" % remote_file)
else:
print("大小不同,文件重新下载...")
download_file(ftp, local_file, remote_file)
else:
# 如果本地文件已存在,但是不完整,则重新下载
if not is_same_size(ftp, local_file, remote_file):
print("大小不同,文件重新下载...")
with open(local_file, 'wb') as f:
print("正在下载:" + remote_file)
ftp.retrbinary('RETR %s' % remote_file, f.write, buf_size)
# 判断文件大小是否相等,不相等则重新下载
if is_same_size(ftp, local_file, remote_file):
print("%s 下载成功" % remote_file)
else:
print("大小不同,文件重新下载...")
download_file(ftp, local_file, remote_file)
else:
print("%s 已存在" % remote_file)
下载目录下的文件(递归目录)
def download_dir(ftp, local_dir, remote_path):
"""
参数:
ftp:FTP()创建的对象
local_dir:本地路径
remote_path:远程目录
"""
local_dir = local_dir + '//' + remote_path
# 如果目录不存在则创建目录
if not os.path.exists(local_dir):
os.makedirs(local_dir) # 可能是多级目录,需要用到makedirs
os.chdir(local_dir) # 切换到下载目录
try:
ftp.cwd(remote_path) # 切换到远程目录
except Exception:
print("%s 不存在" % remote_path)
print("当前ftp路径:" + str(ftp.pwd()))
print("当前下载路径:" + str(os.getcwd()))
file_list = ftp.nlst() # 获取下载文件列表
print("准备下载的文件列表:" + str(file_list))
for file_name in file_list:
# 判断列表各项为目录或是文件
try: # 是目录,递归下载目录
ftp.cwd(file_name) # 判断是否为目录,若是目录则切换到目录下,否则出现异常
ftp.cwd("..") # 切换进目录后需要返回上一级
download_dir(ftp, local_dir, file_name) # 递归下载目录
# 下载后切换到上一级目录
ftp.cwd("..")
os.chdir("..")
except Exception: # 是文件,直接下载
download_file(ftp, file_name, file_name)
测试功能
# 测试上传
def ftp_upload(ftp):
remote_dir = strftime("%Y%m%d") # 远端目录名字以日期命名
local_upload_dir = ".//upload//" # 上传目录
if not os.path.exists(local_upload_dir): # 若上传路径不存在则提示错误信息
print("上传失败")
print("上传路径: " + local_upload_dir + " 不存在")
print("请重新选择正确的上传路径")
return
upload_dir(ftp, local_upload_dir, remote_dir) # 上传目录下的文件
# 测试下载
def ftp_download(ftp):
remote_dir = strftime("%Y%m%d") # 远端目录名字以日期命名
local_download_dir = ".//download//" # 下载目录
if not os.path.exists(local_dir): # 若下载路径不存在则创建目录
os.makedirs(local_dir)
os.chdir(local_dir) # 切换到下载目录
download_dir(ftp, str(os.getcwd()), remote_dir) # 下载目录下的文件
if __name__ == '__main__':
Port = 21 # 端口号默认为21
ip = "10.20.30.40" # 目标IP地址
Username = "username" # 用户名
Password = "password" # 密码
FObj = ftp_connect(ip, Port, Username, Password) # 连接FTP
# FObj.encoding = "gbk" # 传输路径含有中文时需要更改编码
if FObj != "": # 连接成功
# 上传和下载分开测试
ftp_upload(FObj)
# ftp_download(FObj)
FObj.close() # 结束FTP服务
总结
Python语法这块不是很难,主要用到的就只有ftplib的几个方法而已。难点在于搞懂目录结构以及目录之间的切换,搞懂如何在本地和FTP服务器上创建目录。
源码
源代码放在GitHub
参考博客
Python实现的FTP上传和下载功能
Python实现(Linux)FTP上传本地文件和目录
Python实现(Linux)FTP下载远端文件和目录