Извлечение файла bz2 с одним файлом в памяти

У меня есть файл CSV, сжатый в файл BZ2, который я пытаюсь загрузить с веб-сайта, распаковать и записать в локальный файл CSV с помощью

# Get zip file from website
archive = StringIO()
url_data = urllib2.urlopen(url)
archive.write(url_data.read())

# Extract the training data
data = bz2.decompress(archive.read())

# Write to csv
output_file = open('dataset_' + mode + '.csv', 'w')
output_file.write(data)

На распаковке я получаю IOError: invalid data stream, Как примечание, файл csv, содержащийся в архиве, содержит довольно много символов, которые могут вызывать некоторые проблемы. В частности, если я пытаюсь поместить содержимое файла в Unicode, я получаю ошибку о невозможности декодирования 0xfd, У меня есть только один файл в архиве, но мне интересно, может ли что-то происходить из-за не извлечения конкретного файла.

Есть идеи?

1 ответ

Решение

Я подозреваю, что вы получаете эту ошибку, потому что поток, который вы передаете decompress() функция не является допустимым потоком bz2.

Вы также должны "перемотать" свой StringIO буфер после записи в него. Смотрите примечания ниже в комментариях. Следующий код (такой же, как у вас, за исключением импорта, и seek() исправить) работает, если URL указывает на действительный файл bz2.

from StringIO import StringIO
import urllib2
import bz2

# Get zip file from website
url = "http://www.7-zip.org/a/7z920.tar.bz2"  # just an example bz2 file

archive = StringIO()

# in case the request fails (e.g. 404, 500), this will raise
# a `urllib2.HTTPError`
url_data = urllib2.urlopen(url)

archive.write(url_data.read())

# will print how much compressed data you have buffered.
print "Length of file:", archive.tell()

# important!... make sure to reset the file descriptor read position
# to the start of the file.
archive.seek(0)

# Extract the training data
data = bz2.decompress(archive.read())

# Write to csv
output_file = open('output_file', 'w')
output_file.write(data)

Re: проблемы кодирования

Как правило, ошибки кодировки символов будут генерировать UnicodeError (или один из его двоюродных братьев), но не IOError, IOError предполагает, что что-то не так с вводом, например усечение или какая-то ошибка, которая не позволяет декомпрессору полностью выполнить свою работу.

Вы исключили импорт из своего вопроса, и одно из тонких различий между StringIO а также cStringIO (в соответствии с документами) является то, что cStringIO не может работать со строками Unicode, которые не могут быть преобразованы в ascii. Кажется, что это больше не имеет места (по крайней мере, в моих тестах), но может быть в игре.

В отличие от модуля StringIO, этот модуль (cStringIO) не может принимать строки Unicode, которые нельзя кодировать как простые строки ASCII.

Другие вопросы по тегам