Использование zstandard для сжатия файла в Python

#python #zstandard

#python #zstandard

Вопрос:

Итак, я использую библиотеку zstandard python, и я написал вспомогательный класс и функцию для использования контекстов для распаковки файлов.

 class ZstdReader:
    def __init__(self, filename):
        self.filename = filename

    def __enter__(self):
        self.f = open(self.filename, 'rb')
        dctx = zstd.ZstdDecompressor()
        reader = dctx.stream_reader(self.f)
        return io.TextIOWrapper(reader, encoding='utf-8')

    def __exit__(self, *a):
        self.f.close()
        return False

def openZstd(filename, mode='rb'):
    if 'w' in mode:
        return ZstdWriter(filename)
    return ZstdReader(filename)
  

Это работает очень хорошо и позволяет мне просто использовать with openZstd('filename.zst', 'rb') as f: перед использованием файл f для json выгрузки и загрузки.
Однако у меня возникли проблемы с обобщением этого для написания, я попытался следовать документации так же, как я делал до сих пор, но что-то не работает. Вот что я пробовал:

 class ZstdWriter:
    def __init__(self, filename):
        self.filename = filename

    def __enter__(self):
        self.f = open(self.filename, 'wb')
        ctx = zstd.ZstdCompressor()
        writer = ctx.stream_writer(self.f)
        return io.TextIOWrapper(writer, encoding='utf-8')

    def __exit__(self, *a):
        self.f.close()
        return False
  

Когда я открываю файл, используя этот класс, и выполняю a json.dump([], f) , файл по какой-то причине оказывается пустым. Я предполагаю, что одним из шагов является проглатывание моего ввода, но понятия не имею, что это может быть.

Комментарии:

1. Я не знаком с zstandard , но я бы предположил ctx , что либо writer объекты or должны иметь какую-то явную close() flush() операцию or, выполняемую над ними, чтобы убедиться, что любые буферизованные данные действительно записываются.

2. @jasonharper если я удаляю оболочку, средство записи и дескриптор файла, то файл не является пустым и распаковывает нужное содержимое, но zstd CLI жалуется на преждевременное завершение…

3. Из документации: «Если flush(FLUSH_FRAME) не вызывается, передаваемые данные не составляют полный фрейм zstd, и потребители этих данных могут жаловаться на неправильный ввод». Возможно, вы вызывали flush() с другим параметром?

Ответ №1:

Как было предложено jasonharper в комментариях, вы должны очистить как io оболочку, так и сам writer следующим образом:

 s = json.dumps({})
iw = io.TextIOWrapper(writer, encoding="utf-8")
iw.write(s)

iw.flush()
writer.flush(zstd.FLUSH_FRAME)
f.close()
  

Это приводит к тому, что данные находятся в файле, а файл завершен.