Извлечение файла 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.