このコードは、アップロードされたzipファイルをHTTPマルチパートPOST経由で受信し、内部のデータの読み取り専用処理を行うDjangoアプリのコードを簡略化したものです。
#!/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ファイル内の1つまたは2つのCSVファイルを開きます。
奇妙なことに、これを大きなzipファイル(〜13 MB)で実行し、ZipFile
fromStringIO.StringIO
またはa io.BytesIO
(おそらくプレーンファイル名以外のもの)をインスタンス化すると、DjangoアプリでZipFile
fromを作成しようとしたときに同様の問題が発生しました。および)を呼び出して作成されたTemporaryUploadedFile
ファイルオブジェクトでさえ、1つではなく2つのcsvファイルを開くと、処理の終わりに向かって失敗します。Linuxシステムで表示される出力は次のとおりです。os.tmpfile()
shutil.copyfileobj()
$ ./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.
ちなみに、コードは同じ条件下で失敗しますが、私のOSXシステムでは異なる方法で失敗します。例外の代わりに、BadZipfile
破損したデータを読み取るように見え、非常に混乱します。
これはすべて、私がこのコードであなたがしてはいけないことをしていることを私に示唆しています-例えば:zipfile.open
同じzipファイルオブジェクト内の別のファイルをすでに開いている間にファイルを呼び出しますか?を使用する場合、これは問題ではないようですが、モジュール内の実装の詳細のために、ファイルのようなオブジェクトZipFile(filename)
を渡す場合はおそらく問題がありますか?ZipFile
zipfile
おそらく私はzipfile
ドキュメントで何かを逃しましたか?それともまだ文書化されていませんか?または(最も可能性が低い)、zipfile
モジュールのバグですか?