Python中默认安装的ftplib模块定义了FTP类,可用来实现简单的ftp客户端,用于上传或下载文件。
ftplib模块常用方法
ftp登陆连接 from ftplib import FTP #加载ftp模块 ftp=FTP() #设置变量 ftp.set_debuglevel(2) #打开调试级别2,显示详细信息 ftp.connect("IP","port") #连接的ftp sever和端口 ftp.login("user","password") #连接的用户名,密码 print ftp.getwelcome() #打印出欢迎信息 ftp.cmd("xxx/xxx") #进入远程目录 bufsize=1024 #设置的缓冲区大小 filename="filename.txt" #需要下载的文件 file_handle=open(filename,"wb").write #以写模式在本地打开文件 ftp.retrbinaly("RETR filename.txt",file_handle,bufsize) #接收服务器上文件并写入本地文件 ftp.set_debuglevel(0) #关闭调试模式 ftp.quit() #退出ftp ftp相关命令操作 ftp.cwd(pathname) #设置FTP当前操作的路径 ftp.dir() #显示目录下所有目录信息 ftp.nlst() #获取目录下的文件 ftp.mkd(pathname) #新建远程目录 ftp.pwd() #返回当前所在位置 ftp.rmd(dirname) #删除远程目录 ftp.delete(filename) #删除远程文件 ftp.rename(fromname, toname)#将fromname修改名称为toname。 ftp.storbinaly("STOR filename.txt",file_handel,bufsize) #上传目标文件 ftp.retrbinary("RETR filename.txt",file_handel,bufsize) #下载FTP文件
FTP.quit()与FTP.close()的区别
- FTP.quit():发送QUIT命令给服务器并关闭掉连接。这是一个比较“缓和”的关闭连接方式,但是如果服务器对QUIT命令返回错误时,会抛出异常。
- FTP.close():单方面的关闭掉连接,不应该用在已经关闭的连接之后,例如不应用在FTP.quit()之后。
下载、上传文件
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @Time : 2018/8/6 17:17
# @File : ftpclient.py
# @Software: PyCharm
# FTP操作
from ftplib import FTP # 加载ftp模块
from ftplib import error_perm
from utils import file_util
import os
import time
import socket
from concurrent.futures import ThreadPoolExecutor
host = '127.0.0.1'
username = 'egon'
password = '123456'
file = '1.txt'
port = 2111
def ftpconnect(host, port, username, password):
ftp = FTP()
# ftp.set_debuglevel(2) #打开调试级别2,显示详细信息
ftp.encoding = 'utf-8' # 解决中文编码问题,默认是latin-1
try:
ftp.connect(host, port) # 连接
ftp.login(username, password) # 登录,如果匿名登录则用空串代替即可
print(ftp.getwelcome()) # 打印欢迎信息
except(socket.error, socket.gaierror): # ftp 连接错误
print("ERROR: cannot connect [{}:{}]" .format(host, port))
return None
except error_perm: # 用户登录认证错误
print("ERROR: user Authentication failed ")
return None
return ftp
def is_ftp_file(ftp_conn, ftp_path):
try:
if ftp_path in ftp_conn.nlst(os.path.dirname(ftp_path)):
return True
else:
return False
except error_perm:
return False
def downloadfile(ftp, remotepath, localpath):
"""
下载文件
:param ftp:
:param remotepath:
:param localpath:
:return:
"""
bufsize = 1024 # 设置缓冲块大小
fp = open(localpath, 'wb') # 以写模式在本地打开文件
res = ftp.retrbinary(
'RETR ' + remotepath,
fp.write,
bufsize) # 接收服务器上文件并写入本地文件
if res.find('226') != -1:
print('download file complete', localpath)
ftp.set_debuglevel(0) # 关闭调试
fp.close() # 关闭文件
def uploadfile(ftp, remotepath, localpath):
"""
上传文件
:param ftp:
:param remotepath:
:param localpath:
:return:
"""
bufsize = 1024
fp = open(localpath, 'rb')
res = ftp.storbinary('STOR ' + remotepath, fp, bufsize) # 上传文件
if res.find('226') != -1:
print('upload file complete', remotepath)
ftp.set_debuglevel(0)
fp.close()
def ftp_theadpool(func, ftp, file_list):
"""
通过线程池调用上传文件列表
:param func:
:param file_list:
:return:
"""
pool = ThreadPoolExecutor(6)
for remotepath, localpath in file_list:
pool.submit(func, ftp, remotepath, localpath)
pool.shutdown()
if __name__ == "__main__":
ftp = ftpconnect(host, port, username, password)
file_list = ftp.nlst()
print(file_list)
# 将传输模式改为二进制模式 ,避免提示 ftplib.error_perm: 550 SIZE not allowed in ASCII
# mode错误
ftp.voidcmd('TYPE I')
file_size = ftp.size("sqldeveloper-3.1.07.42.zip") # 文件大小
print('filesize [{}]'.format(file_util.bytes2human(file_size)))
start = time.time()
downloadfile(ftp, "sqldeveloper-3.1.07.42.zip", "e:/x.zip")
end = time.time()
print('consume time [{}]'.format(end - start))
if '20180910' not in file_list: # 创建目录
res = ftp.mkd('20180910')
print('mk ', res)
ftp.cwd('20180910') # 进入到新目录
print("FTP当前路径:", ftp.pwd())
print("文件信息:", ftp.nlst())
uploadfile(ftp, "testup.zip", "e:/x.zip") # 上传文件
# ftp.cwd('20180910')
# pwd_path = ftp.pwd()
# print("FTP当前路径:", pwd_path)
# print("文件信息:", ftp.nlst())
ftp.quit()
带进度条下载文件
from ftplib import FTP from ftplib import error_perm import os import socket import time from utils import file_util class FTP_OPS(object): def __init__(self, host, username, password, port): """ 初始化ftp :param host: ftp主机ip :param username: ftp用户名 :param password: ftp密码 :param port: ftp端口 (默认21) """ self.host = host self.username = username self.password = password self.port = port def ftp_connect(self): """ 连接ftp :return: """ ftp = FTP() ftp.encoding = 'utf-8' ftp.set_debuglevel(2) # 开启调试模式 try: ftp.connect(host=self.host, port=self.port) # 连接ftp ftp.login(self.username, self.password) # 登录ftp print(ftp.getwelcome()) # 打印欢迎信息 except(socket.error, socket.gaierror): # ftp 连接错误 print("ERROR: cannot connect [{}:{}]".format(host, port)) return None except error_perm: # 用户登录认证错误 print("ERROR: user Authentication failed ") return None return ftp def download_file(self, ftp_file_path, dst_file_path): """ 从ftp下载文件到本地 :param ftp_file_path: ftp下载文件 :param dst_file_path: 本地存放 :return: """ buffer_size = 10240 # 默认是8192 ftp = self.ftp_connect() print(ftp.getwelcome()) #显示登录ftp信息 # 将传输模式改为二进制模式 ,避免提示 ftplib.error_perm: 550 SIZE not allowed in ASCII ftp.voidcmd('TYPE I') remote_file_size = ftp.size(ftp_file_path) # 文件大小 print('remote filesize [{}]'.format(remote_file_size)) cmpsize = 0 lsize = 0 # check local file isn't exists and get the local file size if os.path.exists(dst_file_path): lsize = os.stat(dst_file_path).st_size if lsize >= remote_file_size: print('local file is bigger or equal remote file') return start = time.time() conn = ftp.transfercmd('RETR {0}'.format(ftp_file_path), lsize) f = open(dst_file_path, "ab") while True: data = conn.recv(buffer_size) if not data: break f.write(data) cmpsize += len(data) print( '\n', 'download process:%.2f%%' % (float(cmpsize) / remote_file_size * 100)) # ftp.retrbinary( # 'RETR {0}'.format(ftp_file_path), # f.write, # buffer_size) f.close() ftp.voidcmd('NOOP') print('keep alive cmd success') ftp.voidresp() print('No loop cmd') conn.close() end = time.time() print('consume time [{}]'.format(end - start)) file_size = os.stat(dst_file_path).st_size print('local filesize [{}] md5:[{}]'.format( file_size, file_util.get_md5(dst_file_path))) ftp.quit() if __name__ == '__main__': host = "10.0.0.1" username = "test" password = "test" port = "21" ftp_file_path = "/data/an/1.zip" dst_file_path = "/data/tmp/1.zip" ftp = FTP_OPS(host=host, username=username, password=password, port=port) ftp.download_file(ftp_file_path=ftp_file_path, dst_file_path=dst_file_path)