【问题标题】:ftp sending python bytesio streamftp 发送 python bytesio 流
【发布时间】:2013-06-07 19:42:19
【问题描述】:

我想用 python ftplib 将文件从一个 ftp 站点发送到另一个站点,以避免文件读/写进程。

我创建了一个 BytesIO 流:

myfile=BytesIO()

并且我使用 retrbinary 从 ftp 站点一成功检索了图像文件:

ftp_one.retrbinary('RETR P1090080.JPG', myfile.write)

我可以将此内存对象保存到常规文件中:

fot=open('casab.jpg', 'wb')

fot=myfile.readvalue()

但我无法通过 ftp 与 storbinary 发送此流。我认为这会起作用:

ftp_two.storbinary('STOR magnafoto.jpg', myfile.getvalue())

但没有。我收到一个以 'buf = fp.read(blocksize) 结尾的长错误消息 AttributeError: 'str' 对象没有属性 'read'

我也尝试了许多荒谬的组合,但都没有成功。顺便说一句,我对 myfoto.write 的真正用途也很困惑。不应该是 myfoto.write() 吗?

我也对这个缓冲区的作用或要求一无所知。我想要实现的目标太复杂了吗?我应该只在系统中使用中间写入/读取来 ping pong 文件吗?都来了

编辑:感谢 abanert,我把事情搞清楚了。作为记录,storbinary 参数是错误的,并且需要一个 myfile.seek(0) 在发送之前“倒回”流。这是一个有效的 sn-p,可以在两个 ftp 地址之间移动文件,而无需中间物理文件写入:

import ftplib as ftp
from io import BytesIO

ftp_one=ftp.FTP(address1, user1, pass1)
ftp_two=ftp.FTP(address2, user2, pass2)
myfile=BytesIO()
ftp_one.retrbinary ('RETR imageoldname.jpg', myfile.write)
myfile.seek(0)
ftp_two.storbinary('STOR imagenewname.jpg', myfile)
ftp_one.close()
ftp_two.close()
myfile.close()

【问题讨论】:

  • 旁注:“我可以将此内存对象保存到常规文件中”实际上根本没有保存信息。 fot=open('casab.jpg', 'wb') 创建一个新的空文件,然后fot=myfile.readvalue() 忘记了文件对象,将其替换为字符串。你需要像fot.write(myfile.readvalue()) 这样的东西来实际写入文件。 (您可能需要也可能不需要先myfile.seek(0)。)
  • 非常感谢您提示 BytesIO 流需要使用 seek(0)“倒带”!这解决了我上传成功但文件为空的问题 \o/

标签: python file memory ftplib bytesio


【解决方案1】:

问题是你打电话给getvalue()。只是不要这样做:

ftp_two.storbinary('STOR magnafoto.jpg', myfile)

storbinary 需要一个可以调用read 的类文件对象。

幸运的是,你有这样一个对象,myfile,一个BytesIO。 (从您的代码中并不能完全清楚这里的事情顺序 - 如果这不能按原样工作,您可能需要 myfile.seek(0) 或以不同的模式或其他方式创建它。但是 BytesIO 将工作storbinary 除非你做错了什么。)

但不是传递myfile,而是传递myfile.getvalue()。和getvalue "返回包含缓冲区全部内容的bytes。"

因此,不是给storbinary 一个可以调用read 的类文件对象,而是给它一个bytes 对象,这当然与Python 2 中的str 相同。 x,你不能打电话给read


在你身边:

顺便说一句,我对 myfoto.write 的真正用途也很困惑。不应该是 myfoto.write() 吗?

看看the docs。第二个参数不是文件,是回调函数。

callback 函数为接收到的每个数据块调用,单个字符串参数给出数据块。

您想要的是一个将每个数据块附加到myfoto 末尾的函数。虽然您可以编写自己的函数来做到这一点:

def callback(block_of_data):
    myfoto.write(block_of_data)

... 很明显,这个函数与myfoto.write 方法的作用完全相同。因此,您可以只传递该方法本身。

如果您不了解绑定方法,请参阅教程中的Method Objects


这种灵活性,虽然看起来很奇怪,但让您做的事情甚至比将整个文件下载到缓冲区以发送到另一台服务器更好。实际上,您可以同时打开两个连接,并使用回调将每个缓冲区从源服务器接收到目标服务器,而无需存储超过一个缓冲区。

但是,除非您真的需要,否则您可能不想经历所有这些复杂性。

事实上,一般来说,ftplib 是一种低级的。它有一些设计(比如storbinary 获取文件,而retrbinary 获取回调)在低级别完全有意义,但从更高级别看起来很奇怪。因此,您可能想通过search at PyPI 来查看一些更高级别的库。

【讨论】:

  • 我做到了,将 myfile 传递给 storbinary。它确实创建了一个文件,但长度为 0 字节。
  • @jose:好吧,如果你想调试它,你必须发布一个完整的例子,但最有可能的是我在答案中已经提到的那个:如果你创建一个空的读取-写BytesIO,然后写进去,然后从里面读取,你从头开始读,所以没有什么可读的。您可以通过从可写BytesIO 的缓冲区中创建一个新的可读BytesIO 来解决此问题,或者只是在其上调用seek(0)
  • 是的,这是有道理的。我明天检查。在没有正确研究文件流的情况下玩弄文件流是我的错。我不知道这些流有读取位置。求你的帮助
  • 玩弄它们是一种很好的学习方式。也许尝试在交互式解释器中玩弄小程序,在那里您可以直接看到每一步发生了什么,而不是试图根据与服务器交互的更大程序的效果进行猜测。但一般不要放弃通过实验学习!
  • 好的,试过了,一个简单的 myfile.seek(0) 就可以了。谢谢,abanert,将编辑主要帖子以保存到将来。我在 Idle 中玩弄工具,但有两个障碍(误读 storbinary 中的参数并忽略了“倒带”数据流的需要)我很迷茫。
猜你喜欢
  • 2021-04-06
  • 2018-04-10
  • 2014-01-26
  • 2014-06-25
  • 1970-01-01
  • 1970-01-01
  • 2010-11-19
  • 1970-01-01
  • 2019-12-13
相关资源
最近更新 更多