2016-08-23 3 views
0

У меня есть большой список объектов dict. Я хотел бы сохранить этот список в tar-файле для обмена удаленно. Я сделал это успешно, написав строку json.dumps() для объекта tarfile, открытого в режиме «w: gz».Сбрасывание JSON непосредственно в tarfile

Я пытаюсь выполнить реализацию по каналам, открыв объект tarfile в режиме «w | gz». Вот мой код:

from json import dump 
from io import StringIO 
import tarfile 

with StringIO() as out_stream, tarfile.open(filename, 'w|gz', out_stream) as tar_file: 
    for packet in json_io_format(data): 
     dump(packet, out_stream) 

Этот код находится в функции 'write_data'. 'json_io_format' - это генератор, который возвращает один объект dict за раз из набора данных (так что пакет является dict).

Вот моя ошибка:

Traceback (most recent call last): 
    File "pdml_parser.py", line 35, in write_data 
    dump(packet, out_stream) 
    File "/.../anaconda3/lib/python3.5/tarfile.py", line 2397, in __exit__ 
    self.close() 
    File "/.../anaconda3/lib/python3.5/tarfile.py", line 1733, in close 
    self.fileobj.close() 
    File "/.../anaconda3/lib/python3.5/tarfile.py", line 459, in close 
    self.fileobj.write(self.buf) 
TypeError: string argument expected, got 'bytes' 

После некоторого поиска неисправностей с помощью комментариев, ошибка вызвана, когда «с» заявление завершает работу, и пытается вызвать контекст менеджера __exit__. I BELIEVE что это в свою очередь вызывает TarFile.close(). Если я удалить вызов tarfile.open() от «с» заявление, и целенаправленно оставить из TarFile.close(), я получаю этот код:

with StringIO() as out_stream: 
    tarfile.open(filename, 'w|gz', out_stream) as tar_file: 
    for packet in json_io_format(data): 
     dump(packet, out_stream) 

Эта версия завершает программу, но не произвести выходной файл «filname» и дает эту ошибку:

Exception ignored in: <bound method _Stream.__del__ of <targile._Stream object at 0x7fca7a352b00>> 
Traceback (most recent call last): 
    File "/.../anaconda3/lib/python3.5/tarfile.py", line 411, in __del__ 
    self.close() 
    File "/.../anaconda3/lib/python3.5/tarfile.py", line 459, in close 
    self.fileobj.write(self.buf) 
TypeError: string argument expected, got 'bytes' 

Я считаю, что это вызвано сборщиком мусора. Что-то препятствует закрытию объекта TarFile.

Может ли кто-нибудь помочь мне разобраться, что здесь происходит?

+1

Ваше исключение не происходит во время цикла, а скорее в конце блока 'with' (который находится после окончания цикла). В вызове '__close__' менеджера контекста tarfile возникают проблемы с данными, которые я не совсем понимаю (таким образом, это комментарий, а не ответ). Чтобы упростить отладку, вы могли бы протестировать, просто используя 'dump'ing одно значение без цикла. – Blckknght

+0

Я переписал функцию, чтобы удалить объявление tarfile из инструкции with и получил ту же ошибку. Я удалил tar_file.close(), и теперь я получаю ошибку, когда сборщик мусора пытается удалить объект потока. Так что да, что-то не так с закрытием tarfile. Я поправлю свой вопрос, чтобы отразить это, спасибо за подсказку. – kingledion

ответ

1

Почему, по-вашему, вы можете написать tarfile для StringIO? Это не работает, как вы думаете.

Этот подход не является ошибкой, но на самом деле вы не создаете tarfile в памяти из объектов в памяти.

from json import dumps                
from io import BytesIO              
import tarfile                  

data = [{'foo': 'bar'},                
     {'cheese': None},                
     ]                    

filename = 'fnord'                 
with BytesIO() as out_stream, tarfile.open(filename, 'w|gz', out_stream) as tar_file: 
    for packet in data:                
     out_stream.write(dumps(packet).encode())          
+0

Что я пытался сделать, так это использовать StringIO для заполнения tarfile. Я хотел сделать это по-разному, так что я обрабатываю данные и загружаю их через канал в этот скрипт, в то время как этот скрипт будет передавать эти данные в формате json в tar-файл. Время от времени я собираю tar-файл и отправляю его. Я получаю впечатление от вашего ответа, что то, что я на самом деле делаю, отправляет tarfile в выходной поток. Я не понимаю, как я это делаю. – kingledion

+0

Когда вы говорите 'piped manner', вы на самом деле имеете в виду' in memory'? Потому что это две разные вещи, и это выглядит так, как будто вы пытаетесь сделать последнее. Если это так, то, что вы хотите делать *, это создание tarfile, как я делаю с 'BytesIO', потому что hey, tarfiles являются двоичными! То, что вы делаете дальше, зависит от того, нужен ли вам один файл с кучей данных JSON (который не является допустимым файлом JSON) или если вы хотите, чтобы в вашем tar была куча файлов JSON.Вы можете либо a) открыть один файл, и когда он станет достаточно большим, tar его и отправить его или b) открыть файл для каждого фрагмента данных –

Смежные вопросы