此代码是 Django 应用程序中代码的简化,该应用程序通过 HTTP 多部分 POST 接收上传的 zip 文件,并对内部数据进行只读处理:
#!/usr/bin/env python
import csv, sys, StringIO, traceback, zipfile
try:
import io
except ImportError:
sys.stderr.write('Could not import the `io` module.\n')
def get_zip_file(filename, method):
if method == 'direct':
return zipfile.ZipFile(filename)
elif method == 'StringIO':
data = file(filename).read()
return zipfile.ZipFile(StringIO.StringIO(data))
elif method == 'BytesIO':
data = file(filename).read()
return zipfile.ZipFile(io.BytesIO(data))
def process_zip_file(filename, method, open_defaults_file):
zip_file = get_zip_file(filename, method)
items_file = zip_file.open('items.csv')
csv_file = csv.DictReader(items_file)
try:
for idx, row in enumerate(csv_file):
image_filename = row['image1']
if open_defaults_file:
z = zip_file.open('defaults.csv')
z.close()
sys.stdout.write('Processed %d items.\n' % idx)
except zipfile.BadZipfile:
sys.stderr.write('Processing failed on item %d\n\n%s'
% (idx, traceback.format_exc()))
process_zip_file(sys.argv[1], sys.argv[2], int(sys.argv[3]))
很简单。我们打开 zip 文件和 zip 文件中的一两个 CSV 文件。
奇怪的是,如果我用一个大的 zip 文件(~13 MB)运行它并让它实例化ZipFile
from aStringIO.StringIO
或 a io.BytesIO
(也许不是普通文件名?我在 Django 应用程序中尝试创建ZipFile
from时遇到了类似的问题aTemporaryUploadedFile
甚至是通过调用os.tmpfile()
and shutil.copyfileobj()
) 创建的文件对象,并让它打开两个 csv 文件,而不仅仅是一个,然后它在处理结束时失败。这是我在 Linux 系统上看到的输出:
$ ./test_zip_file.py ~/data.zip direct 1
Processed 250 items.
$ ./test_zip_file.py ~/data.zip StringIO 1
Processing failed on item 242
Traceback (most recent call last):
File "./test_zip_file.py", line 26, in process_zip_file
for idx, row in enumerate(csv_file):
File ".../python2.7/csv.py", line 104, in next
row = self.reader.next()
File ".../python2.7/zipfile.py", line 523, in readline
return io.BufferedIOBase.readline(self, limit)
File ".../python2.7/zipfile.py", line 561, in peek
chunk = self.read(n)
File ".../python2.7/zipfile.py", line 581, in read
data = self.read1(n - len(buf))
File ".../python2.7/zipfile.py", line 641, in read1
self._update_crc(data, eof=eof)
File ".../python2.7/zipfile.py", line 596, in _update_crc
raise BadZipfile("Bad CRC-32 for file %r" % self.name)
BadZipfile: Bad CRC-32 for file 'items.csv'
$ ./test_zip_file.py ~/data.zip BytesIO 1
Processing failed on item 242
Traceback (most recent call last):
File "./test_zip_file.py", line 26, in process_zip_file
for idx, row in enumerate(csv_file):
File ".../python2.7/csv.py", line 104, in next
row = self.reader.next()
File ".../python2.7/zipfile.py", line 523, in readline
return io.BufferedIOBase.readline(self, limit)
File ".../python2.7/zipfile.py", line 561, in peek
chunk = self.read(n)
File ".../python2.7/zipfile.py", line 581, in read
data = self.read1(n - len(buf))
File ".../python2.7/zipfile.py", line 641, in read1
self._update_crc(data, eof=eof)
File ".../python2.7/zipfile.py", line 596, in _update_crc
raise BadZipfile("Bad CRC-32 for file %r" % self.name)
BadZipfile: Bad CRC-32 for file 'items.csv'
$ ./test_zip_file.py ~/data.zip StringIO 0
Processed 250 items.
$ ./test_zip_file.py ~/data.zip BytesIO 0
Processed 250 items.
顺便说一句,代码在相同的条件下失败,但在我的 OS X 系统上以不同的方式失败。而不是BadZipfile
异常,它似乎读取了损坏的数据并且变得非常困惑。
这一切都向我表明,我在这段代码中做了一些你不应该做的事情——例如:zipfile.open
在同一个 zip 文件对象中已经打开另一个文件的同时调用一个文件?使用时这似乎不是问题ZipFile(filename)
,但在传递ZipFile
类似文件的对象时可能会出现问题,因为zipfile
模块中的一些实现细节?
也许我错过了zipfile
文档中的某些内容?或者它可能还没有记录?或者(最不可能)zipfile
模块中的错误?