Python 2.7: сжатие данных в формате XZ с использованием модуля lzma

Я экспериментирую с модулем lzma в Python 2.7.6, чтобы посмотреть, смогу ли я создавать сжатые файлы с использованием формата XZ для будущего проекта, в котором он будет использоваться. Мой код, использованный во время эксперимента, был таким:

import lzma as xz

in_file = open('/home/ki2ne/Desktop/song.wav', 'rb')
input_data = in_file.read()

compressed_data = xz.compress(input_data)
out_file = open('/home/ki2ne/Desktop/song.wav.xz', 'wb')
in_file.close()
out_file.close()

и я заметил, что в результирующем файле были две разные контрольные суммы (MD5 и SHA256) по сравнению с тем, когда я использовал простой xz (хотя я мог нормально распаковать любой метод - контрольные суммы распакованных версий обоих файлов были одинаковыми). Будет ли это проблемой?

ОБНОВЛЕНИЕ: я нашел исправление, установив backport (из Python 3.3) через Git-репозиторий peterjc (ссылка здесь), и теперь он показывает идентичные контрольные суммы. Не уверен, что это поможет, но я убедился, что модуль LZMA Python в моем репозитории не установлен, чтобы избежать возможных конфликтов имен.

Вот мой тестовый код, чтобы подтвердить это:

# I have created two identical text files with some random phrases

from subprocess import call
from hashlib import sha256
from backports import lzma as xz

f2 = open("test2.txt" , 'rb')
f2_buf = buffer(f2.read())
call(["xz", "test1.txt"])

f2_xzbuf = buffer(xz.compress(f2_buf))
f1 = open("test1.txt.xz", 'rb')
f1_xzbuf = buffer(f1.read())

f1.close(); f2.close()

f1sum = sha256(); f2sum = sha256()

f1sum.update(f1_xzbuf); f2sum.update(f2_xzbuf)

if f1sum.hexdigest() == f2sum.hexdigest():
    print "Checksums OK"
else:
    print "Checksum Error"

Я также проверил это, используя обычную sha256sum (когда я записывал данные в файл).


person ki2ne    schedule 13.03.2014    source источник
comment
Надеюсь, вы когда-нибудь написали out_file.   -  person Peter Gibson    schedule 13.03.2014
comment
К сожалению, я упустил это в примере, но да, я записал файл в самом скрипте.   -  person ki2ne    schedule 13.03.2014


Ответы (2)


Меня бы не беспокоили различия в сжатых файлах — в зависимости от формата контейнера и типа контрольной суммы, используемой в файле .xz, сжатые данные могли меняться, не влияя на содержимое.

EDIT Я изучал это дальше и написал этот скрипт для тестирования модуля PyLZMA Python2.x и встроенного модуля lzma Python3.x.

from __future__ import print_function
try:
    import lzma as xz
except ImportError:
    import pylzma as xz
import os

# compress with xz command line util
os.system('xz -zkf test.txt')

# now compress with lib
with open('test.txt', 'rb') as f, open('test.txt.xzpy', 'wb') as out:
    out.write(xz.compress(bytes(f.read())))

# compare the two files
from hashlib import md5

with open('test.txt.xz', 'rb') as f1, open('test.txt.xzpy', 'rb') as f2:
    hash1 = md5(f1.read()).hexdigest()
    hash2 = md5(f2.read()).hexdigest() 
    print(hash1, hash2)
    assert hash1 == hash2

Это сжимает файл test.txt с помощью утилиты командной строки xz и модуля Python и сравнивает результаты. В Python3 lzma дает тот же результат, что и xz, однако в Python2 PyLZMA дает другой результат, который нельзя извлечь с помощью утилиты командной строки xz.

Какой модуль вы используете, который называется «lzma» в Python2, и какую команду вы использовали для сжатия данных?

EDIT 2 Хорошо, я нашел модуль pyliblzma для Python2. Однако похоже, что он использует CRC32 в качестве алгоритма контрольной суммы по умолчанию (другие используют CRC64), и есть ошибка, которая не позволяет изменить алгоритм контрольной суммы https://bugs.launchpad.net/pyliblzma/+bug/1243344

Возможно, вы могли бы попробовать сжать с помощью xz -C crc32, чтобы сравнить результаты, но мне все еще не удается создать действительный сжатый файл с использованием библиотек Python2.

person Peter Gibson    schedule 13.03.2014
comment
Спасибо за разъяснения. Я собирался задаться вопросом, что, если я создам архивы .tar.xz с помощью Python и распространяю их, кто-нибудь может указать на это и забеспокоиться, что его можно подделать. - person ki2ne; 13.03.2014
comment
Я использую пакет python-lzma из моего дистрибутива для модуля, который я использую в скрипте. Я протестировал сжатие данных с помощью сценария из моего примера и с помощью команды xz из пакета xz-utils (используя сеанс терминала вне сценария). Я проверил файлы обоих методов, используя md5sum и sha256sum. - person ki2ne; 14.03.2014

В моем случае (Ubuntu/Mint), чтобы использовать модуль lzma с Pyhton 2.7, я установил backports.lzma напрямую с pip (я не использовал github), с пользователем sudo или root:

pip2 install backports.lzma

К вашему сведению pip2 имеет параметр --user, который не требует прав суперпользователя и устанавливает модуль только для локального пользователя, но я не проверял его.

Прежде чем выполнить установку pip, вы также должны установить с помощью менеджера пакетов одну обязательную зависимость: библиотеку liblzma.

В моем случае имена пакетов были liblzma5 и liblzma-dev, но имена пакетов могут различаться в разных дистрибутивах/выпусках Linux.

P.s. Я также успешно повторил ту же операцию с conda в другой среде Linux (неизвестный кластерный дистрибутив):

conda install backports
conda install backports.lzma --name pyEnvName

Надеюсь, полезно

person Fabiano Tarlao    schedule 14.08.2018