Этот код является упрощением кода в приложении Django, которое получает выгруженный zip-файл через HTTP, состоящий из нескольких частей POST, и выполняет обработку данных только для чтения внутри:
#!/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-файл и один или два CSV-файла внутри zip-файла.
Что странного в том, что если я запускаю это с большим zip-файлом (~ 13 МБ) и создаю для него экземпляр ZipFile
из StringIO.StringIO
или io.BytesIO
(возможно, из-за простого имени файла? У меня было аналогичные проблемы в приложении Django при попытке создать ZipFile
из TemporaryUploadedFile
или даже файлового объекта, созданного путем вызова os.tmpfile()
и 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
?