web-dev-qa-db-ja.com

python)でのzlib解凍

さて、Pythonの(2.6)zlib.compress()関数で圧縮されたデータストリームがいくつかあります。それらを解凍しようとすると、解凍されないものがあります(zlibエラー-5、これは「バッファエラー」のようですが、どうすればよいかわかりません)。最初は完了したと思っていましたが、解凍できなかったものはすべて0x78DA(動作しているものは0x789C)から始まっていることに気付き、周りを見回すと、別の種類のzlib圧縮のようです。使用する圧縮によってマジックナンバーが変わります。ファイルを解凍するには何を使用できますか?私は馬鹿ですか?

10
X.R.

RFC 195 によると、「OK」0x789Cと「bad」0x78DAの違いはFLEVELビットフィールドにあります。

  FLEVEL (Compression level)
     These flags are available for use by specific compression
     methods.  The "deflate" method (CM = 8) sets these flags as
     follows:

        0 - compressor used fastest algorithm
        1 - compressor used fast algorithm
        2 - compressor used default algorithm
        3 - compressor used maximum compression, slowest algorithm

     The information in FLEVEL is not needed for decompression; it
     is there to indicate if recompression might be worthwhile.

「OK」は2を使用し、「bad」は3を使用します。したがって、それ自体の違いは問題ではありません。

さらに詳しく知りたい場合は、圧縮と(試行された)解凍のそれぞれについて、次の情報を提供することを検討してください。プラットフォーム、Pythonのバージョン、zlibライブラリのバージョン、zlibモジュールの呼び出しに使用される実際のコードは何ですか。また、失敗した解凍の試行からの完全なトレースバックとエラーメッセージを提供します。失敗したファイルを他のzlib読み取りソフトウェアで解凍しようとしましたか?どのような結果になりますか?何を処理する必要があるかを明確にしてください:「私はホースで止められていますか?」元のデータにアクセスできないということですか?ストリームからファイルにどのように移行しましたか?データが送信中に壊れていないことをどのように保証しますか?

[〜#〜] update [〜#〜]自己回答で公開された部分的な説明に基づくいくつかの観察:

Windowsを使用しています。 Windowsは、ファイルの読み取りと書き込みを行うときに、バイナリモードとテキストモードを区別します。テキストモードで読み取る場合、Python 2.xは '\ r\n'を '\ n'に変更し、書き込み時に '\ n'を '\ r\n'に変更します。これはテキスト以外のデータを処理する場合はお勧めできません。さらに悪いことに、テキストモードで読み取る場合、「\ x1a」(別名Ctrl-Z)はファイルの終わりとして扱われます。

ファイルを圧縮するには:

# imports and other superstructure left as a exercise
str_object1 = open('my_log_file', 'rb').read()
str_object2 = zlib.compress(str_object1, 9)
f = open('compressed_file', 'wb')
f.write(str_object2)
f.close()

ファイルを解凍するには:

str_object1 = open('compressed_file', 'rb').read()
str_object2 = zlib.decompress(str_object1)
f = open('my_recovered_log_file', 'wb')
f.write(str_object2)
f.close()

余談ですが、gzipモジュールを使用すると、追加のヘッダー情報に数バイトのコストがかかりますが、テキストモードのような厄介なことを考える必要がなくなります。

圧縮コードで「rb」と「wb」を使用しているが、解凍コードでは使用していない場合[可能性は低いですか?]、問題はありません。上記の解凍コードを具体化して実行する必要があります。

次の未テストのアイデアでは、「may」、「should」などの使用に注意してください。

圧縮コードで「rb」と「wb」を使用していない場合は、自分でホースを使用している可能性がかなり高くなります。

元のファイルに「\ x1a」のインスタンスがあった場合、最初のインスタンス以降のデータはすべて失われますが、その場合、解凍時に失敗することはありません(このシナリオは症状と一致しません)。

Ctrl-Zがzlib自体によって生成された場合、解凍を試みると早期にEOF)が発生し、もちろん例外が発生します。この場合、プロセスを簡単に逆にすることができます。圧縮ファイルをバイナリモードで読み取り、「\ r\n」を「\ n」に置き換えます[つまり、Ctrl-Zなしでテキストモードをシミュレートします-> EOFギミック]。結果を解凍します。Edit結果をTEXTモードで書き出します。End edit

UPDATE 2次のスクリプトを使用して、レベル1から9までの症状を再現できます。

import zlib, sys
fn = sys.argv[1]
level = int(sys.argv[2])
s1 = open(fn).read() # TEXT mode
s2 = zlib.compress(s1, level)
f = open(fn + '-ct', 'w') # TEXT mode
f.write(s2)
f.close()
# try to decompress in text mode
s1 = open(fn + '-ct').read() # TEXT mode
s2 = zlib.decompress(s1) # error -5
f = open(fn + '-dtt', 'w')
f.write(s2)
f.close()

注:解凍結果に「\ x1a」が含まれるようにするには、適度に大きなテキストファイル(80kbのソースファイルを使用)を使用する必要があります。

このスクリプトで回復できます:

import zlib, sys
fn = sys.argv[1]
# (1) reverse the text-mode write
# can't use text-mode read as it will stop at Ctrl-Z
s1 = open(fn, 'rb').read() # BINARY mode
s1 = s1.replace('\r\n', '\n')
# (2) reverse the compression
s2 = zlib.decompress(s1)
# (3) reverse the text mode read
f = open(fn + '-fixed', 'w') # TEXT mode
f.write(s2)
f.close()

注:元のファイルに「\ x1a」(別名Ctrl-Zバイト)があり、ファイルがテキストモードで読み取られる場合、そのバイトとそれに続くすべてのバイトは圧縮ファイルに含まれません。 、したがって、回復できません。テキストファイル(ソースコードなど)の場合、これはまったく損失ではありません。バイナリファイルの場合、あなたはおそらく馬鹿にされています。

アップデート3[問題に関与している暗号化/復号化レイヤーがあるという遅い暴露に続いて]:

「エラー-5」メッセージは、解凍しようとしているデータが圧縮されてからマングルされていることを示しています。ファイルでテキストモードを使用したことが原因ではない場合、疑いは明らかに(?)復号化および暗号化ラッパーにあります。ヘルプが必要な場合は、それらのラッパーのソースを明らかにする必要があります。実際、あなたがやるべきことは(私がしたように)複数の入力ファイルで問題を再現する小さなスクリプトをまとめることです。次に(私が行ったように)、どのような条件下でプロセスを逆にできるかを確認します。第2段階で支援が必要な場合は、問題再現スクリプトを公開する必要があります。

29
John Machin

探していた

python -c 'import sys,zlib;sys.stdout.write(zlib.decompress(sys.stdin.read()))'

自分で書いた; Pythonでのzlib解凍 の回答に基づく

3
166_MMX

前回の投稿について申し訳ありませんが、すべてが揃っていませんでした。また、OpenIDを使用していなかったため、投稿を編集できません。とにかく、ここにいくつかのデータがあります:

1)解凍トレースバック:

Traceback (most recent call last):
  File "<my file>", line 5, in <module>
    zlib.decompress(data)
zlib.error: Error -5 while decompressing data

2)圧縮コード:

#here you can assume the data is the data to be compressed/stored
data = encrypt(zlib.compress(data,9)) #a short wrapper around PyCrypto AES encryption
f = open("somefile", 'wb')
f.write(data)
f.close()

3)解凍コード:

f = open("somefile", 'rb')
data = f.read()
f.close()

zlib.decompress(decrypt(data)) #this yeilds the error in (1)
0
X R

申し訳ありませんが、私は十分に明確ではありませんでした。これはwin32ですpython2.6.2。zlibファイルが見つからないのではないかと思いますが、win32バイナリリリースに含まれているものは何でもです。アクセスできません。元のデータ-ログファイルを圧縮していて、元に戻したいのですが、他のソフトウェアに関しては、7Zipを試してみましたが、gzipではなくzlibであるため、もちろん失敗しました( zlibストリームを直接解凍するソフトウェアはありませんでした)現在、トレースバックのカーボンコピーを提供することはできませんが、(zlib.decompress(data)にトレースバック)zlib.error:エラー:-3です。 、明確にするために、これらは静的ファイルであり、以前に聞こえたようにストリームではありません(したがって、送信エラーはありません)。また、コードがないのではないかと思いますが、zlib.compress(data、 9)(つまり、最高の圧縮レベルで-興味深いことに、最高レベルに配置したため、すべてのzlib出力が78daであるとは限らないようです)、zlib.decompress()だけです。

0
x r