python - Python 3 ftp 类的正确使用

标签 python python-3.x ftp

作为仍在学习该语言的 Python 新手,我花了几天时间尝试使用 ftplib 中的 ftp 类(运行 Python 3.3)进行简单的 ASCII 文件传输(STOR/PUT)。

在使用 storbinary() 方法并持续收到 TypeError: "Type str does not support the buffer API"后,我发现了此线程上的讨论,这意味着 ftplib 到 Python 的端口存在错误3:

http://bugs.python.org/issue6822

然后我尝试使用 storbinary() 而不是 storlines(),使用使用“rb”开关打开的文件对象,它似乎工作得很好。我正在 Windows 系统上工作,出于测试/学习目的,我将上传到我自己的 Linux 主机上的网站。上传 .zip 和 .txt 文件并使用 FileZilla 将它们复制回我的工作站后,这两个文件都完好无损。

在日常工作中,我需要将 gzip 压缩和 ASCII 文件上传到大型机,并且担心使用这种违反直觉的解决方法可能会让自己面临文件传输错误。当我忘记切换到适当的传输模式时,我搞砸了很多手动 FTP 传输,能够使用完全相同的代码传输二进制和 ASCII 文件感觉令人毛骨悚然!

任何人都可以评论我如何实现这个库类吗?

谢谢。

fileName = 'F:\\Data_Folder\\Test_File.txt'
fileParts = os.path.split(fileName)
putFile = fileParts[1]
cmd = 'STOR {}'.format(putFile)
fileObject = open(fileName, 'rb')
ftp.storbinary(cmd, fileObject)

fileName = 'F:\\Data_Folder\\Test_File.zip'
fileParts = os.path.split(fileName)
putFile = fileParts[1]
cmd = 'STOR {}'.format(putFile)
fileObject = open(fileName, 'rb')
ftp.storbinary(cmd, fileObject)

2013 年 6 月 28 日 - 回到这里来解决这个问题。 虽然我可以将 open(fileName, 'rb') 与 ftp.storbinary() 一起成功用于二进制和 ASCII 文本文件,并以 Windows 和 Linux 主机作为目标,但当我以大型机作为目标时,文本文件出现乱码,显示为二进制文件。

通过向我的包装类添加一个开关以继续使用“rb”参数打开文件,但使用 storlines() 进行传输,文件会完好无损地到达目的地。我愿意打赌,主机端可能有一些配置选项,可能会使这种行为在一台主机和另一台主机之间有所不同,但我希望提及这一点能够提醒遇到此线程的任何人,显然“open(fileName, 'rb') 和 storbinary() 的“安全”组合可能无法在所有 FTP 主机上成功,尤其是大型机系统。它可能只能通过反复试验来确定,但在某些情况下,传输 ASCII 数据的正确方法需要 open(fileName, 'rb') 和 storlines() 一起使用。

最佳答案

storlines 的 3.3 文档明确表示:

Lines are read until EOF from the file object file (opened in binary mode)…

因此,向其传递以文本模式打开的文件是行不通的。

FTP 的文本 (ASCII) 模式与 Python 的文本模式不同。特别是,FTP 文本要求为 ASCII(并且是真正的 7 位 ASCII,而不是值 > 127 的扩展代码页)。但 Python 文本具有明确指定的字符集,并被视为 Unicode。如果您的文件实际上是 UTF-8、Latin-1、CP-850 等,则无法使用文本模式。

最重要的是,Python 和 FTP 都可以修改文本文件的行结尾。有时您想要这样,因此您可以将 Windows 文本文件上传到 Linux 机器,并让它以 Unix 行结尾而不是 Windows 的形式显示(尽管这实际上可能不会发生,具体取决于各种情况)事物…)。但除此之外,您不想使用文本模式。

简而言之,您以二进制模式打开文本文件并以二进制(图像)模式上传它们可能是正确的做法。


同时,您的代码按原样来说就很好,但如果您正在寻找改进方法,那么总是有进行细微更改的空间。

首先,如果您将相同的 7 行复制并粘贴了两次,唯一的区别是 1 行中的字符串,请将其分解到函数中。

此外,请关闭您的文件。添加显式 fileObject.close(),或者更好的是使用 with 语句。如果您的短期脚本中只有 2 个文件,则不会有太大区别,但这仍然是一个好主意 - 您稍后可能会将其扩展为打开 2 个以上文件或生命周期更长的脚本。

如果您只需要文件的基本名称,则调用 basename 比调用 split 然后访问 [1] 更清晰。

进入挑剔的阶段,除非您有大量使用不同样式的“遗留”或包装器代码,否则最好坚持使用 PEP 8而不是发明自己的风格。

最后,如果您想保留以不同方式发送文本和二进制文件的可能性,即使目前它们的实现相同,只需编写 upload_binary_fileupload_text_file >,并使后者调用第二个,或者是对同一函数的引用。但是,您可能想要这个。由于上述原因以及 J.F. Sebastian 的评论,upload_text_file 函数更有可能是一种误导性的、有吸引力的麻烦,而不是 future 扩展的有用钩子(Hook)。

所以:

def upload_file(filename):
    put_file = os.path.basename(filename)
    cmd = 'STOR {}'.format(put_file)
    with open(filename, 'rb') as file_object:
        ftp.storbinary(cmd, file_object)

upload_file('F:\\Data_Folder\\Test_File.txt')
upload_file('F:\\Data_Folder\\Test_File.zip')

关于python - Python 3 ftp 类的正确使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16447479/

相关文章:

python - 向后移植 Python 3. 4's regular expression "fullmatch()"到 Python 2

python-3.x - 如何在 python 3 控制台中打印出导入库的成员函数?

c# - 没有 session 关闭的FTP Webrequest多个文件

python - 多处理 : farming out python functions to a cluster

python - flatc 是否验证给定 JSON 的 Flatbuffer 模式的必填字段?

python - Pandas 无法像我期望的那样工作 apply

python - Django CMS Aldryn 创建向导数据库错误

python-3.x - Python浮点精度和

c# - Fluent FTP 无法连接到 FTP 服务器

c# - 从公共(public)服务器上的 PHP 页面向 C# 发送数据/命令