开发FTP文件传输程序—Python编程从入门到精通(9)

发表于:2018-12-28 11:36

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:叶维忠    来源:51Testing软件测试网原创

  17.6、开发FTP文件传输程序
  在计算机网络领域中,远程文件传输又是一个重要的分支。在计算机的7层协议当中,TCP、FTP、Telnet、UDP可以实现远程文件处理。作为一门功能强大的开发语言,Python可以实现对远程文件的处理。本章将详细讲解使用Python语言开发远程文件传输系统的过程。
  17.6.1、Python和FTP
  当使用Python语言编写FTP客户端程序时,需要将相应的Python 模块ftplib导入项目程序中。具体开发流程如下所示。
  (1)连接到服务器。
  (2)登录。
  (3)发出服务请求(希望能得到响应)。
  (4)退出。
  在使用Python语言开发FTP程序时,首先需要导入,然后实例化一个ftplib.FTP类对象,所有的FTP 操作(如登录、传输文件和注销等)都要使用这个对象完成。使用类FTP可以创建一个FTP连接对象。具体语法格式如下所示。
  FTP(host, user, passwd, acct)
  "host:要连接的FTP服务器,可选参数。
  "user:登录FTP服务器所使用的用户名,可选参数。
  "passwd:登录FTP服务器所使用的密码,可选参数。
  "acct:可选参数,默认为空。
  在内置模块ftplib的FTP类中,主要包含如下所示常用的方法。
  (1)方法set_debuglevel()。
  当创建一个FTP连接对象以后,可以使用方法set_debuglevel()设置调试级别。其语法格式如下。
  set_debuglevel (level)
  参数level是指调试级别,默认的调试级别为0。
  (2)方法connect()。
  如果在创建FTP连接对象时没有使用参数host,则可以使用FTP对象中的方法connect(),其语法格式如下。
  connect(host,port,timeout,source-address)
  "host:要连接的FTP服务器。
  "port:FTP服务器的端口,可选参数。
  (3)方法login()。
  如果在创建FTP对象时没有使用用户名和密码,则可以通过FTP对象中的方法login()使用用户名和密码登录FTP服务器。其语法格式如下。
  login (user, passwd, acct)
  "user:登录FTP服务器所使用的用户名。
  "passwd:登录FTP服务器所使用的密码。
  "acct:可选参数,默认为空。
  (4)方法getwelcome()、sendcmd()和voidcmd()。
  使用FTP对象中的方法getwelcome()可以获得FTP服务器的欢迎信息。使用FTP对象中的方法abort()可以中断文件传输。使用FTP对象中的方法sendcmd()和方法voidcmd()可以向FTP服务器发送命令,这两个方法的不同之处在于voidcmd()方法没有返回值。这两个方法的语法格式如下。
  sendcmd( command)
  voidcmd( command)
  参数command是指向服务器发送的命令字符串。
  (5)方法retrbinary()和方法retrlines()。
  使用FTP对象中的方法retrbinary()和方法retrlines()可以从FTP服务器下载文件。不同的是,retrbinary()方法使用二进制形式传输文件,而retrlines()方法使用ASCII形式传输文件。其语法格式如下。
  retrbinary(command, callback, maxblocksize, rest)
  retrlines (command,  callback)
  对于retrbinary()方法,各个参数的具体含义如下所示。
  "command:传输命令,由"RETR+文件名"组成(之间有空格)。
  "callback:传输回调函数。
  "maxblocksize:设置每次传输的最大字节数,可选参数。
  "rest:设置文件续传位置,可选参数。
  对于retrlines()方法,各个参数的具体含义如下所示。
  "command:传输命令。
  "callback:传输回调函数。
  (6)方法storbinary()和方法storlines()。
  使用FTP对象中的方法storbinary()和方法storlines()可以向FTP服务器上传文件。这两个方法的不同之处是storbinary()方法使用二进制形式传输文件,而storlines()方法使用ASCII码形式传输文件。这两个方法的语法格式如下。
  storbinary(command, file, blocksize)
  storlines (command,  file)
  对于storbinary()方法,各个参数的具体含义如下所示。
  "command:传输命令,由"STOR+文件名"组成(之间有空格)。
  "file:本地文件句柄。
  "blocksize:设置每次读取文件的最大字节数,可选参数。
  对于storlines()方法,各个参数的含义如下。
  "command:传输命令。
  "file:本地文件句柄。
  (7)方法set_pasv()。
  使用FTP对象中的方法set_pasv()可以设置传输模式。具体语法格式如下所示。
  set_pasv (boolean)
  如果参数boolean为True,则为被动模式;如果为False,则为主动模式。
  (8)方法dir()和方法rename()。
  使用FTP对象中的方法dir()可以获取当前目录中内容列表。使用FTP对象中的方法rename()可以修改FTP服务器中的文件名。具体语法格式如下所示。
  rename (fromname,  toname)
  "fromname:原来文件名。
  "toname:重命名后的文件名。
  (9)方法delete()。
  使用FTP对象中的方法delete()可以从FTP服务器上删除文件。具体语法格式如下所示。
  delete( filename)
  参数filename是要删除的文件名。
  (10)方法cwd()。
  使用FTP对象中的方法cwd()可以改变当前目录。具体语法格式如下所示。
  cwd (pathname)
  参数pathname是要进入目录的路径。
  (11)方法mkd()。
  使用FTP对象中的方法mkd()可以在FTP服务器上创建目录。具体语法格式如下所示。
  mkd (pathname)
  参数pathname表示要创建目录的路径。
  (12)方法pwd()。
  使用FTP对象中的方法pwd()可以获得当前目录。
  (13)方法rmd()。
  使用FTP对象中的方法rmd()可以删除FTP服务器上的目录。具体语法格式如下所示。
  rmd (dirname)
  参数dirname表示要删除的目录。
  (14)方法size()。
  使用FTP对象中的方法size()可以获得文件的大小。具体语法格式如下所示。
  size(filename)
  参数filename表示要获取文件大小的文件名。
  (15)方法quit()和方法close()。
  使用FTP对象中的方法quit()和方法close()可以关闭与FTP服务器的连接。
  17.6.2、创建一个FTP文件传输客户端
  下面的实例代码演示了使用ftplib库创建一个简单的FTP文件传输客户端的过程。
  实例17-8 创建一个简单的FTP文件传输客户端
  源码路径 daima\17\17-8
  实例文件ftp.py的具体实现代码如下所示。
from ftplib import FTP  #导入FTP
bufsize = 1024          #设置缓冲区的大小
def Get(filename):      #定义函数Get()下载文件
command = 'RETR ' + filename #变量command初始化
#下载FTP文件
ftp.retrbinary(command, open(filename,
'wb').write, bufsize)
print('下载成功')   #下载成功提示
def Put(filename):      #定义函数Put()上传文件
command = 'STOR ' + filename #变量command初始化
filehandler = open(filename,'rb')#打开指定文件
ftp.storbinary(command,filehandler,bufsize) #实现文件上传操作
filehandler.close()      #关闭连接
print('上传成功')         #显示提示
def PWD():                    #定义获取当前目录的函数PWD()
print(ftp.pwd())         #返回当前所在位置
def Size(filename):           #定义获取文件大小的函数Size()
print(ftp.size(filename))#显示文件大小
def Help():                   #定义系统帮助函数Help()
print('''                #开始显示帮助提示
==================================
Simple Python FTP
==================================
cd         进入文件夹
delete     删除文件
dir        获取当前文件列表
get        下载文件
help       帮助
mkdir      创建文件夹
put        上传文件
pwd        获取当前目录
rename     重命名文件
rmdir      删除文件夹
size       获取文件大小
''')
server = input('请输入FTP服务器地址:') #信息输入
ftp = FTP(server)                    #获取服务器地址
username = input('请输入用户名:')      #输入用户名
password = input('请输入密码:')        #输入密码
ftp.login(username,password)         #使用用户名和密码登录FTP服务器
print(ftp.getwelcome())              #显示欢迎信息
#定义一个字典actions,在里面保存操作命令
actions  = {'dir':ftp.dir, 'pwd': PWD, 'cd':ftp.cwd, 'get':Get,
'put':Put, 'help':Help, 'rmdir': ftp.rmd,
'mkdir': ftp.mkd, 'delete':ftp.delete,
'size':Size, 'rename':ftp.rename}
while True:                          #执行循环操作
print('pyftp>')                 #显示提示符
cmds = input()                  #获取用户的输入
cmd = str.split(cmds)           #使用空格分隔用户输入的内容
try:                            #异常处理
if len(cmd) == 1:          #验证输入命令中是否有参数
if str.lower(cmd[0]) == 'quit': #如果输入的命令是quit,则退出循环
break
else:
actions[str.lower(cmd[0])]()     #调用与输入的命令对应的操作函数
elif len(cmd) == 2:        #处理只有一个参数的命令
actions[str.lower(cmd[0])](cmd[1])   #调用与输入的命令对应的操作函数
elif len(cmd) == 3:        #处理有两个参数的命令
actions[str.lower(cmd[0])](cmd[1],cmd[2]) #调用与输入的命令对应的操作函数
else:                      #如果是其他情况
print('输入错误')      #显示错误提示
except:
print('命令出错')
ftp.quit()                           #退出系统
  运行上述实例代码后,会要求输入FTP服务器的地址、用户名和密码。如果正确输入上述信息则完成FTP服务器登录,并显示一个"pyftp>"提示符,等待用户输入命令。如果输入"dir"和"pwd"这两个命令,就会调用和执行对应的命令操作函数。在测试和运行本实例代码时,需要有一个FTP服务器及登录该服务器的用户名和密码。如果读者没有互联网中的FTP服务器,可以尝试在本地计算机中通过IIS配置一个FTP服务器,然后进行测试。执行后的效果如图17-10所示。
  17.7、解析XML
  XML是指可扩展置标语言(eXtensible Markup Language),标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。在现实应用中,常见的XML编程接口有两种,分别是SAX和DOM。所以与之对应的是,Python语言有两种解析XML文件的方法,分别是SAX和DOM方法。本节将详细讲解使用Python语言解析XML文件的知识。
  17.7.1、SAX解析方法
  在Python语言的标准库中包含了SAX解析器,SAX通过使用事件驱动模型,在解析XML的过程中触发一个个的事件并调用用户定义的回调函数来处理XML文件。
  SAX是一种基于事件驱动的API,当利用SAX解析XML文档时会涉及如下两部分。
  "解析器:负责读取XML文档,并向事件处理程序发送事件,例如元素开始与元素结束事件。
  "事件处理器:负责对事件做出响应,对传递的XML数据进行处理。
  当在Python程序中使用SAX方式处理XML文件时,需要先引入文件xml.sax中的parse()函数,还有xml.sax.handler中的类ContentHandler。其中类ContentHandler中的常用函数如下所示。
  (1)characters(content):调用时机如下所示。
  "从行开始,在遇到标签之前,存在字符,content的值为这些字符串。
  "从一个标签开始,在遇到下一个标签之前,存在字符,content的值为这些字符串。
  "从一个标签开始,在遇到行结束符之前,存在字符,content的值为这些字符串。
  这里标签可以是开始标签,也可以是结束标签。
  (2)startDocument():当启动文档时调用。
  (3)endDocument():当解析器到达文档结尾时调用。
  (4)startElement(name, attrs):当遇到XML开始标签时调用,name是标签的名字,attrs是标签的属性值字典。
  (5)endElement(name):当遇到XML结束标签时调用。
  在xml.sax中的常用内置函数如下所示。
  (1)parse ():通过如下语法格式可以创建一个SAX解析器,并解析XML文档。
  xml.sax.parse( xmlfile, handler[, errorhandler])
  各个参数的具体说明如下所示。
  "xmlfile:XML文件名。
  "handler:必须是一个ContentHandler的对象。
  "errorhandler:如果指定该参数,errorhandler必须是一个SAX ErrorHandler对象。
  (2)parseString():功能是创建一个XML解析器并解析XML字符串。具体语法格式如下所示。
  xml.sax.parseString(xmlstring, contenthandler[, errorhandler])
  各个参数的具体说明如下所示。
  "xmlstring:XML字符串。
  "contenthandler:必须是一个ContentHandler的对象。
  "errorhandler:如果指定该参数,errorhandler必须是一个SAX ErrorHandler对象。
  下面的实例代码演示了使用SAX方法解析XML文件的过程。
  实例17-9 使用SAX方法解析XML文件
  源码路径 daima\17\17-9
  文件movies.xml是一个基本的XML文件,在里面保存一些和电影有关的资料信息。文件movies.xml的具体实现代码如下所示。
<collection shelf="New Arrivals">
<movie title="Enemy Behind">
<type>War, Thriller</type>
<format>DVD</format>
<year>2003</year>
<rating>PG</rating>
<stars>10</stars>
<description>Talk about a US-Japan
</description>
</movie>
<movie title="Transformers">
<type>Anime, Science Fiction</type>
<format>DVD</format>
<year>1989</year>
<rating>R</rating>
<stars>8</stars>
<description>A scientific fiction</description>
</movie>
<movie title="Trigun">
<type>Anime, Action</type>
<format>DVD</format>
<episodes>4</episodes>
<rating>PG</rating>
<stars>10</stars>
<description>Vash the Stampede!</description>
</movie>
<movie title="Ishtar">
<type>Comedy</type>
<format>VHS</format>
<rating>PG</rating>
<stars>2</stars>
<description>Viewable boredom</description>
</movie>
</collection>
  实例文件sax.py的功能是解析文件movies.xml的内容。具体实现代码如下所示。
import xml.sax
class MovieHandler( xml.sax.ContentHandler ):
def __init__ (self):
self.CurrentData = ""
self.type = ""
self.format = ""
self.year = ""
self.rating = ""
self.stars = ""
self.description = ""
#元素开始调用
def startElement(self, tag, attributes):
self.CurrentData = tag
if tag == "movie":
print ("*****Movie*****")
title = attributes["title"]
print ("Title:", title)
#元素结束调用
def endElement(self, tag):
if self.CurrentData == "type":       #处理XML中的type元素
print ("Type:", self.type)
elif self.CurrentData == "format":   #处理XML中的format元素
print ("Format:", self.format)
elif self.CurrentData == "year":     #处理XML中的year元素
print ("Year:", self.year)
elif self.CurrentData == "rating":   #处理XML中的rating元素
print ("Rating:", self.rating)
elif self.CurrentData == "stars":       #处理XML中的stars元素
print ("Stars:", self.stars)
elif self.CurrentData == "description": #处理XML中的description元素
print ("Description:", self.description)
self.CurrentData = ""
# 读取字符时调用
def characters(self, content):
if self.CurrentData == "type":
self.type = content
elif self.CurrentData == "format":
self.format = content
elif self.CurrentData == "year":
self.year = content
elif self.CurrentData == "rating":
self.rating = content
elif self.CurrentData == "stars":
self.stars = content
elif self.CurrentData == "description":
self.description = content
if (__name__ == "__main__"):
# 创建一个XMLReader
parser = xml.sax.make_parser()
# turn off namespaces
parser.setFeature(xml.sax.handler.feature_namespaces, 0)
# 重写ContentHandler
Handler = MovieHandler()
parser.setContentHandler( Handler )
parser.parse("movies.xml")
  执行后的效果如图17-11所示。
  
  17.7.2、DOM解析方法
  DOM是文件对象模型(Document Object Model)的简称,是W3C组织推荐的处理可扩展置标语言的标准编程接口。当一个DOM解析器在解析一个XML文档时,可以一次性读取整个文档。将文档中的所有元素保存在内存中的一个树结构中后,可以利用DOM 提供的不同的函数来读取或修改文档的内容和结构,也可以把修改过的内容写入到XML文件中。
  下面的实例代码演示了使用DOM方法解析XML文件的过程。
  实例17-10 使用DOM方法解析XML文件
  源码路径 daima\17\17-10
  实例文件dom.py的功能是解析文件movies.xml的内容。具体实现代码如下所示。
from xml.dom.minidom import parse
import xml.dom.minidom
#使用minidom解析器打开 XML 文档
DOMTree = xml.dom.minidom.parse("movies.xml")
collection = DOMTree.documentElement
if collection.hasAttribute("shelf"):
print ("Root element : %s" %
collection.getAttribute("shelf"))
#在集合中获取所有电影
movies = collection.getElementsByTagName("movie")
#输出每部电影的详细信息
for movie in movies:
print ("*****Movie*****")
if movie.hasAttribute("title"):
print ("Title: %s" % movie.getAttribute("title"))
type = movie.getElementsByTagName('type')[0]
print ("Type: %s" % type.childNodes[0].data)
format = movie.getElementsByTagName('format')[0]
print ("Format: %s" % format.childNodes[0].data)
rating = movie.getElementsByTagName('rating')[0]
print ("Rating: %s" % rating.childNodes[0].data)
description = movie.getElementsByTagName('description')[0]
print ("Description: %s" % description.childNodes[0].data)
  执行后的效果和实例17-9的一样(见图17-11)。
相关阅读:
21/212>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号