验证来自标准输入的zip文件
在使用unzip(1L)
时遇到了一些麻烦,我试着写一个脚本,可以解压缩并打印出来自标准输入的zip文件里所有文件的原始数据。目前我有以下代码,它是可以工作的:
import sys, zipfile, StringIO
stdin = StringIO.StringIO(sys.stdin.read())
zipselect = zipfile.ZipFile(stdin)
filelist = zipselect.namelist()
for filename in filelist:
print filename, ':'
print zipselect.read(filename)
但是当我尝试添加验证,检查它是否真的是一个zip文件时,程序就不太喜欢这样做。
...
zipcheck = zipfile.is_zipfile(zipselect)
if zipcheck is not None:
print 'Input is not a zip file.'
sys.exit(1)
...
这导致了
File "/home/chris/simple/zipcat/zipcat.py", line 13, in <module>
zipcheck = zipfile.is_zipfile(zipselect)
File "/usr/lib/python2.7/zipfile.py", line 149, in is_zipfile
result = _check_zipfile(fp=filename)
File "/usr/lib/python2.7/zipfile.py", line 135, in _check_zipfile
if _EndRecData(fp):
File "/usr/lib/python2.7/zipfile.py", line 203, in _EndRecData
fpin.seek(0, 2)
AttributeError: ZipFile instance has no attribute 'seek'
我猜它不能进行查找操作是因为这不是一个文件,对吗?
抱歉如果这很明显,这是我第一次尝试用Python。
3 个回答
你在2011年用python2写的代码是:StringIO.StringIO(sys.stdin.read())
而在2018年,一个使用python3的程序员可能会这样写:io.StringIO(...).
你想要的python3代码应该是:io.BytesIO(...). 确实,当我使用requests
模块从网络服务器下载二进制ZIP文件时,这个方法对我来说效果很好:
zf = zipfile.ZipFile(io.BytesIO(req.content))
要完全在内存中完成这个任务,需要一些工作。AttributeError
的错误信息意味着is_zipfile
这个方法正在尝试使用你提供的文件句柄的seek
方法。但是标准输入是不能进行“跳转”的,因此你为它创建的文件对象没有seek
方法。
如果你真的不能暂时把文件存储到磁盘上,那么你可以把整个文件缓存在内存中(不过你需要设置一个大小限制以确保安全),然后实现一些“鸭子”代码,这种代码看起来和行为上像一个可以跳转的文件对象,但实际上只是使用内存中的字节字符串。
你也有可能通过“作弊”的方式,只缓冲足够的数据,让is_zipfile
能够完成它的工作,但我记得ZIP文件的目录信息是在文件的最后面。不过我可能记错了。
你应该把 stdin
传给 is_zipfile
,而不是 zipselect
。is_zipfile
需要的是一个文件的路径或者一个文件对象,而不是一个 ZipFile
。
可以查看 zipfile.is_zipfile 的文档 来了解更多信息。
你说得对,ZipFile
不能进行查找操作,因为它不是一个普通的文件。它是一个压缩包,可以包含很多文件。