我想从一个ftp站点向另一个ftp站点发送带有python ftplib的文件,以避免文件读/写过程。
我创建了一个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())
但不是。我得到一个很长的错误消息msg以'buf = fp.read(blocksize)结尾 AttributeError:'str'对象没有属性'read'
我也试过很多荒谬的组合,但没有成功。顺便说一句,我对myfoto.write真正做的事情也很困惑。不应该是myfoto.write()?
我对这个缓冲区的功能或要求也毫无能力。我想要的实现太复杂了吗?我应该在系统中使用中间写/读来ping文件吗? Ty all
编辑:感谢abanert,我把事情做好了。对于记录,storbinary参数是错误的,并且在发送之前需要myfile.seek(0)来“回放”流。这是一个工作片段,可以在两个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()
答案 0 :(得分:6)
问题在于您正在呼叫getvalue()
。只是不要这样做:
ftp_two.storbinary('STOR magnafoto.jpg', myfile)
storbinary
需要一个类似文件的对象,可以调用read
。
幸运的是,你有一个myfile
,BytesIO
这样的对象。 (从你的代码中不完全清楚事情的顺序是什么 - 如果这不能按原样运行,你可能需要myfile.seek(0)
或以不同的模式或其他方式创建它。但是{{1除非你做错了什么,否则我将使用BytesIO
。)
但不是传递storbinary
,而是传递myfile
。并且getvalue
“返回包含缓冲区全部内容的myfile.getvalue()
。”
所以,不是给bytes
一个类似文件的对象,它可以调用storbinary
,而是给它一个read
对象,当然与{在Python 2.x中{1}},您无法在其上调用bytes
。
暂且不谈:
顺便说一句,我对myfoto.write真正做的事情也很困惑。不应该是myfoto.write()?
看看the docs。第二个参数不是文件,它是一个回调函数。
为接收到的每个数据块调用回调函数,并使用单个字符串参数给出数据块。
您想要的是一个将每个数据块附加到str
末尾的函数。虽然您可以编写自己的函数来执行此操作:
read
...很明显,这个函数与myfoto
方法完全相同。所以,你可以自己传递这个方法。
如果您不了解绑定方法,请参阅教程中的Method Objects。
这种灵活性,看似奇怪,让你做的事情比将整个文件下载到缓冲区以发送到另一台服务器更好。实际上,您可以同时打开这两个连接,并使用回调将每个缓冲区从源服务器发送到目标服务器,而不会存储任何多个缓冲区。
但是,除非你真的需要,否则你可能不想经历所有这些复杂性。
事实上,一般来说,def callback(block_of_data):
myfoto.write(block_of_data)
是一种低级别的。它有一些设计(比如myfoto.write
接受一个文件的事实,而ftplib
接受一个回调)这个事实在这个低级别上完全有意义但从更高级别看起来很奇怪。因此,您可能希望通过执行search at PyPI来查看一些更高级别的库。