linux python ftp下载文件,Python实现FTP下载远端文件和目录

最近在做一个稽核任务,需要FTP登录服务器下载文件到本地,参考了不少例子,功能都太单一,很少能直接拿来使用,于是自己写了一个。

一 . 几个模块

from ftplib import FTP

ftp = FTP() #设置变量

ftp.set_debuglevel(2) #打开调试级别2 显示详细信息

ftp.connect("IP", "port") #连接ftp, IP和端口

ftp.log("user", "password") #连接的用户名、密码

ftp.cwd(pathname) #设置FTP当前操作的路径

ftp.dir() #显示目录下的文件信息

ftp.nlst() #获取目录下的文件

ftp.mkd(pathname) #新建远程目录

ftp.pwd() #返回当前所在位置

ftp.rmd(dirname) #删除远程目录

ftp.delete(filename) #删除远程文件

ftp.rename(from_name, to_name) #修改文件名

ftp.storbinaly("STOR filename.txt", file_handel, bufsize) # 上传目标文件

ftp.retrbinaly("RETR filename.txt", file_handel, bufsize) # 上传FTP文件

二. 功能实现:

1. 下载整个目录包括子目录

def DownLoadFileTree(LocalDir, RemoteDir, ftp, IsRecursively):

入参:LocalDir 本地目录,可以是当前路径

RemoteDir: 远端目录 ,必须是服务器上存在的且有权限访问的目录

ftp : FTP() 创建的类对象

IsRecursively:是否递归即是否下载所有文件包含子目录 True或者False

2. 指定文件名下载

def DownLoadRUledFile(LocalDir, RemoteDir, filename, ftp):

入参:LocalDir 本地目录,可以是当前路径

RemoteDir: 远端目录 ,必须是服务器上存在的且有权限访问的目录

ftp : FTP() 创建的类对象

filename:远端文件名

3.实际负责下载功能的函数

def ftp_download(LocalFile, RemoteFile, bufsize, ftp):

入参:LocalFile:本地写入的文件名,目录在上一个函数已经创建

RemoteFile: 远端文件名, 传入需要下载的文件名即可 此时已经切换到远端目标目录

ftp : FTP() 创建的类对象

bufsize:远端文件的大小

4. 简单的检查函数

def IsDownloadCompletely(RemoteFile, LocalFile, remote_size):

入参:LocalFile:下载完成后本地存在此文件

LocalFile: 远端文件名, 传入远端文件名即可

remote_size:远端文件的大小 用于对比是否一致

三. 代码

可以直接使用,只用修改ftp相关信息和目录,文件名即可,测试通过

说明:在检查是否是目录的时候使用了分解字符函数 split:

dir_list = []

''' 对当前目录进行dir 将结果放入列表'''

ftp.dir('.', dir_list.append)

p_subdir = dif.split(" ")[-1]

因为在linux 系统下,所有文件或目录通过list (ls -lrt) 都显示如下 没有更好的方式获取远端服务器判断是文件或目录。默认linux系统中目录是以d开头+权限+文件大小+日期等:如

drwxr-x---    2 5005     5010         4096 Oct 31 21:10 recycle

而文件则是以-开头,即没有目录的d标志

-rwxr-xr-x    1 5005     5010          792 Nov 12 09:10 rate_proccess_proc.exp

这样就很好理解以上代码了 只用取split分拣字符列表的最后一个元素就是文件或目录的名称。

请看代码吧:

#! /usr/bin/python # -*- coding: utf-8 -*

#import unittest # 单元测试用例

import os

import re

import sys

import datetime,time

from ftplib import FTP # 定义了FTP类,实现ftp上传和下载

import traceback

import logging

LOG_FORMAT = "%(message)s" #"%(asctime)s %(name)s %(levelname)s %(pathname)s %(message)s "#配置输出日志格式

DATE_FORMAT = '%Y-%m-%d %H:%M:%S %a ' #配置输出时间的格式,注意月份和天数不要搞乱了

LOG_PATH = None#os.path.join(os.getcwd(),'./logs/ftpget.log')

logging.basicConfig(level=logging.DEBUG,

format=LOG_FORMAT,

datefmt = DATE_FORMAT ,

filemode='a', #覆盖之前的记录 'a'是追加

filename=LOG_PATH #有了filename参数就不会直接输出显示到控制台,而是直接写入文件

)

'''

@检查是否下载完整

'''

def IsDownloadCompletely(RemoteFile, LocalFile, remote_size):

p = re.compile(r'\\',re.S)

LocalFile = p.sub('/', LocalFile)

localsize = os.path.getsize(LocalFile)

if localsize == remote_size:

print('downloading %s ...Successs! remote_size:%d , local_size:%d.' %(RemoteFile, remote_size, localsize))

logging.debug('downloading %s ... Successs! remote_size:%d , local_size:%d.' %(RemoteFile, remote_size, localsize))

return True

else:

print('downloading %s ...Successs! remote_size:%d , local_size:%d.' %(RemoteFile, remote_size, localsize))

logging.debug('downloading %s ... Successs! remote_size:%d , local_size:%d.' %(RemoteFile, remote_size, localsize))

return False

'''

@实际负责下载功能的函数

'''

def ftp_download(LocalFile, RemoteFile, bufsize, ftp):

# 本地是否有此文件

if not os.path.exists(LocalFile):

with open(LocalFile, 'wb') as f:

ftp.retrbinary('RETR %s' % RemoteFile, f.write, bufsize)

# ftp.set_debuglevel(0) #关闭调试模式

#到这里文件会写入关闭,放在with语句外面

return IsDownloadCompletely(RemoteFile, LocalFile, bufsize)

else:

if not IsDownloadCompletely(RemoteFile, LocalFile, bufsize):

#如果已存在,但是不完整,重新写入覆盖

with open(LocalFile, 'wb+') as f:

ftp.retrbinary('RETR %s' % RemoteFile, f.write, bufsize)

#到这里文件会写入关闭,放在with语句外面

return IsDownloadCompletely(RemoteFile, LocalFile, bufsize)

"""

# 根据文件名前缀下载文件

"""

def DownLoadRUledFile(LocalDir, RemoteDir, filename, ftp):

print("RemoteDir:", RemoteDir)

if not os.path.exists(LocalDir):

os.makedirs(LocalDir)

Local = os.path.join(LocalDir, filename) # 下载到当地的全路径

try:

# 打开该远程目录

ftp.cwd(RemoteDir)

#直接下载

ftp.voidcmd('TYPE I') # 将传输模式改为二进制模式 ,避免提示 ftplib.error_perm: 550 SIZE not allowed in ASCII

bufsize = ftp.size(filename) #服务器里的文件总大小

#print(bufsize)

ftp_download(Local, filename, bufsize, ftp)

except:

print('some error happend in get file:%s. Err:%s' %(filename, traceback.format_exc()))

logging.debug('some error happend in get file:%s. Err:%s' %(filename, traceback.format_exc()))

return

"""

下载整个目录下的文件

"""

def DownLoadFileTree(LocalDir, RemoteDir, ftp, IsRecursively=False):

print("RemoteDir:", RemoteDir)

if not os.path.exists(LocalDir):

print('local directory %s not exists , make it ...')

os.makedirs(LocalDir)

# 打开该远程目录

ftp.cwd(RemoteDir)

dir_list = []

''' 对当前目录进行dir 将结果放入列表'''

ftp.dir('.', dir_list.append)

for dif in dir_list:

if dif.startswith("d"):

if IsRecursively:

''' 该对象为目录 递归下载'''

print('%s is a directory, download it Recursively...' %(dif))

p_subdir = dif.split(" ")[-1]

p_local_subdir = os.path.join(LocalDir, p_subdir)

''' 本地子目录创建原理相同 但不在此处创建 在递归出创建'''

p_remote_subdir = os.path.join(ftp.pwd(), p_subdir)

DownLoadFileTree(p_local_subdir, p_remote_subdir, ftp)

ftp.cwd("..") # 返回路径最外侧

else:

print('%s is a directory, download mode is UnRecursive, continue...' %(dif))

continue

else:

''' 是文件 直接下载 '''

print('%s is a file, download it directly...' %(dif))

p_filename = dif.split(" ")[-1]

bufsize = ftp.size(p_filename) #服务器里的文件总大小

Localfile = os.path.join(LocalDir, p_filename) # 下载到当地的全路径

ftp_download(Localfile, p_filename, bufsize, ftp)

return

if __name__ == '__main__':

host = '1.2.3.4'

port = 21

username = 'hello'

password = 'world'

ftp = FTP()

ftp.connect(host,port)

ftp.login(username, password)

''' 按文件名下载 '''

LocalDir = os.getcwd()

RemoteDir = '/home/li'

filename = 'readme.txt'

#DownLoadRUledFile(LocalDir, RemoteDir, filename, ftp)

''' 递归下载整个目录 '''

IsRecursively = True #是否递归目录下的子目录 开关 是 True 否 False

DownLoadFileTree(LocalDir, RemoteDir, ftp, IsRecursively)

下载的过程显示:

bb9fa7fabae077aa7df018b1d6bd23fa.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值