验证来自标准输入的zip文件

1 投票
3 回答
3460 浏览
提问于 2025-04-16 21:17

在使用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 个回答

0

你在2011年用python2写的代码是:StringIO.StringIO(sys.stdin.read())

而在2018年,一个使用python3的程序员可能会这样写:io.StringIO(...).

你想要的python3代码应该是:io.BytesIO(...). 确实,当我使用requests模块从网络服务器下载二进制ZIP文件时,这个方法对我来说效果很好:

zf = zipfile.ZipFile(io.BytesIO(req.content))
1

要完全在内存中完成这个任务,需要一些工作。AttributeError的错误信息意味着is_zipfile这个方法正在尝试使用你提供的文件句柄的seek方法。但是标准输入是不能进行“跳转”的,因此你为它创建的文件对象没有seek方法。

如果你真的不能暂时把文件存储到磁盘上,那么你可以把整个文件缓存在内存中(不过你需要设置一个大小限制以确保安全),然后实现一些“鸭子”代码,这种代码看起来和行为上像一个可以跳转的文件对象,但实际上只是使用内存中的字节字符串。

你也有可能通过“作弊”的方式,只缓冲足够的数据,让is_zipfile能够完成它的工作,但我记得ZIP文件的目录信息是在文件的最后面。不过我可能记错了。

3

你应该把 stdin 传给 is_zipfile,而不是 zipselectis_zipfile 需要的是一个文件的路径或者一个文件对象,而不是一个 ZipFile

可以查看 zipfile.is_zipfile 的文档 来了解更多信息。

你说得对,ZipFile 不能进行查找操作,因为它不是一个普通的文件。它是一个压缩包,可以包含很多文件。

撰写回答