第一章:连接 FTP 服务器并实现文件夹上传
① 连接 FTP 服务器
如果 FTP 不用用户名密码就直接可以访问,那就是用的默认用户名 Anonymous,密码为空。
# -*- coding: UTF8 -*- # 2022-3-10 # 作者:小蓝枣 # python连接ftp服务器 from ftplib import FTP def conn_ftp(): ''' 作用:连接ftp服务器 参数:无 返回:ftp服务器连接的对象 ''' # FTP连接信息 ftp_ip = "xx.xx.xx.xx" # 默认端口21 ftp_port = 21 # 如果未指定,使用默认用户名为Anonymous,密码为空 ftp_user = "Anonymous" ftp_password = "" ftp = FTP() # 连接ftp ftp.connect(ftp_ip, ftp_port) # ftp登录 ftp.login(ftp_user, ftp_password) # 查看欢迎信息 print(ftp.getwelcome()) return ftp ftp = conn_ftp()
② 区分文件和文件夹名
从方法 ftp.dir()
返回结果可以看到包含 <DIR>
标识的为文件夹,我们根据这个特征来进行文件夹区分。
def diff_dir(ftp, path): ''' 作用:区分文件和文件夹 参数1:ftp连接对象 参数2:要展示的目录 返回:无 ''' # 进入指定目录 ftp.cwd(path) # 显示当前所在位置 print("当前所在位置为:") print(ftp.pwd()) # 展示目录内容 print("\n显示目录内容:") dirs = [] ftp.dir(".", dirs.append) for i in dirs: # 区分文件和文件夹 if("<DIR>" in i): print("目录为:" + i.split(" ")[-1]) else: print("文件为:" + i.split(" ")[-1]) path = "/CaseData/nc.vo.sdp.testcase.testcase.TestcaseHVO/" diff_dir(ftp, path)
③ 文件夹名包含空格处理
split(" ")[-1]
方法有个缺陷,如果文件或文件夹名里包含空格,得到到的文件夹名就不对了,下面的方法可以有效的解决这个问题
def get_dir_name(s): ''' 作用:需要文件或文件夹名 参数1:需要截取的字符串 返回:文件或文件夹名 ''' dir_name = "" k = 0 record = "" for i in s: if(record == " " and i != " "): k = k + 1; if(k >= 3): dir_name = dir_name + i; record = i print(dir_name) return dir_name # 测试两条数据 get_dir_name("03-08-22 09:52AM <DIR> C2021.11_ZDHJC_004a") get_dir_name("03-08-25 10:32AM 89098 hello .exe")
④ 使用递归实现:清理指定目录下所有的文件和非空文件夹
为什么强调非空呢,因为如果文件夹非空是没法直接删除的,只有当文件夹里的所有内容都删掉,文件夹为空时才可以删除。
import os def dir_clear(ftp, dir_name): ''' 作用: 目录清空处理 参数1:ftp连接对象 参数2:目录或文件名 返回:无 ''' # 进入指定目录 ftp.cwd(dir_name) dirs = [] ftp.dir(".", dirs.append) for i in dirs: try: if("<DIR>" in i): new_dir_name = get_dir_name(i) # 非空目录还删不了,先删除目录里的文件 dir_clear(ftp, new_dir_name) ftp.rmd(new_dir_name) elif("<DIR>" not in i): new_file_name = get_dir_name(i) ftp.delete(new_file_name) except Exception as e: print("删除失败脚本:" + get_dir_name(i)) print("失败原因:" + e) # 退出当前目录 ftp.cwd("..") path = "/CaseData/nc.vo.sdp.testcase.testcase.TestcaseHVO/" # 文件清空 dir_clear(ftp, path)
执行后可以看到所有的文件和文件夹都被清空了:
⑤ 使用递归实现:本地文件上传FTP服务器里的文件夹
思路:
1、并判断是否是目录,如果是目录的话,本地根据目录结构进行递归,同时在 FTP 服务器的对应位置创建文件夹。
2、需要判断原来的目录下是否存在同名的文件或文件夹,是的话要进行删除,这里用 delete_dir() 方法来实现,非空文件夹不能直接删除,还要进行递归处理,用上面的 dir_clear() 方法来实现。
3、由于文件和文件夹可以同名,但是不是同一种类型,怕误删,这里根据同名并同种类型来判断,如果原来列表里的文件较多,判断同类型的方法需要列表遍历,再加上上传的文件较多就会反复遍历列表影响效率,所以加个 current_dir 字符串的变量,可以先检查是否有同名的,如果没有直接跳过,提升效率,有的话再进行二次遍历。
注意:由于是一个 ftp 连接对象,递归过程中进去某个目录下,递归结束要回到之前的目录。
import pathlib def delete_dir(ftp, isdir, dir_name, current_dir): ''' 作用: 判断目录或文件是否存在,存在的话删除 参数1:ftp连接对象 参数2:是否为目录,是的话为目录,不是的话为文件 参数3:目录或文件名 参数4:当前目录下的列表文件名集 返回:无 ''' # 先初步判断下,不然直接循环遍历量大的影响效率 if(dir_name not in current_dir): return dirs = [] ftp.dir(".", dirs.append) for i in dirs: if(isdir == True and "<DIR>" in i): if(dir_name == get_dir_name(i)): # 非空目录还删不了,先删除目录里的文件 dir_clear(ftp, dir_name) ftp.rmd(dir_name) elif(isdir == False and "<DIR>" not in i): if(dir_name == get_dir_name(i)): ftp.delete(dir_name) def upload_dir(ftp, path, local_path): ''' 作用: 上传目录 参数1:ftp连接对象 参数2:远程路径 参数3:本地存放路径 返回:无 ''' print(path) # 进入指定目录 ftp.cwd(path) # 获取当前目录的一个列表 current_dir = "" for i in ftp.nlst(): current_dir = current_dir + " " + i # 遍历本地路径 for i in os.listdir(local_path): new_local_path = local_path + '/' + i # 判断为文件 if(os.path.isfile(new_local_path)): # 如果有同名文件,删除 delete_dir(ftp, False, i, current_dir) f = open(new_local_path, 'rb') # 上传文件 ftp.storbinary("STOR " + i, f) f.close() # 判断为文件夹 elif(os.path.isdir(new_local_path)): # 如果有同名文件夹,删除 delete_dir(ftp, True, i, current_dir) # 创建目录 print(i) try: ftp.mkd(i) upload_dir(ftp, i, new_local_path); except Exception as e: print("文件夹上传失败:" + get_dir_name(i)) print("失败原因:" + e) # 退出当前目录 ftp.cwd("..") # 设置编码,解决上传的文件包含中文的问题 ftp.encoding = 'GBK' path = "/CaseData/nc.vo.sdp.testcase.testcase.TestcaseHVO/" local_path = "D:/ftp上传" upload_dir(ftp, path, local_path)
这是本地的路径。
这里服务器路径,可以看到里面的嵌套目录也同步被上传了。
第二章:相关问题
① 上传的文件名包含中文【‘utf-8’ codec can’t decode byte …】
设置下 FTP 对象的编码为 GBK 即可。
ftp.encoding = 'GBK'
不然会报如下错误:UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd7 in position 114: invalid continuation byte
② 指定的路径存在问题【550 The system cannot find the file specified.】
开始我用 split(" ")[-1]
方法截取文件名,由于有的文件含有中文,截取后的文件名称不对了。
就报了 ftplib.error_perm: 550 The system cannot find the file specified.
的错误。
③ 上传文件前未加STOR标识【500 Command not understood.】
上传文件时 FTP 路径前要加个 'STOR '
,不然就会报 500 错误,注意后面还跟了个空格。
# 上传文件 ftp.storbinary("STOR " + i, f)
不然就报 ftplib.error_perm: 500 Command not understood.
错误了。
④ 上传文件夹包含中文名【暂未解决】
目前 ftp.mkd(i)
方法创建文件夹时如果包含中文名时会报错,暂未找到解决方法。
喜欢的点个赞❤吧!