5

重複の可能性:
コンテンツ全体を読み取らずに zip ファイルを末尾にするにはどうすればよいですか?

抽出すると 25GB を超える 7GB の gzip syslog ファイルがあります。ファイル全体を一度にメモリに読み込まずに、ファイルの最初と最後の行だけを取得する必要があります。

GzipFile()Python 2.7 ではwith、ヘッドを読み取るために を使用できます (withファイル全体を読み取る必要がないことを意味します)。

>>> from itertools import islice
>>> from gzip import GzipFile
>>> with GzipFile('firewall.4.gz') as file:
...     head = list(islice(file, 1))
>>> head
['Oct  2 07:35:14 192.0.2.1 %ASA-6-305011: Built dynamic TCP translation 
from INSIDE:192.0.2.40/51807 to OUTSIDE:10.18.61.38/2985\n']

AttributeError: GzipFile instance has no attribute '__exit__'( GzipFile () は GzipFile()でのwith反復をサポートしていないため)...

>>> from itertools import islice
>>> from gzip import GzipFile
>>> class GzipFileHack(GzipFile):
...     def __enter__(self):
...         return self
...     def __exit__(self, type, value, tb):
...         self.close()
>>> with GzipFileHack('firewall.4.gz') as file:
...     head = list(islice(file, 1))

これに関する問題は、末尾を取得する方法がないことです...islice()負の値をサポートしていないため、25 GB のファイルを反復せずに最後の行を取得する方法が見つかりません (時間がかかりすぎます)。

ファイル全体をメモリに読み取ったり、すべての行を反復処理したりせずに、gzip テキスト ファイルの末尾を読み取る最も効率的な方法は何ですか? これができない場合は、その理由を説明してください。

4

3 に答える 3

13

gzip で使用される deflate 形式は、データの直前の 32K のどこかで一致する文字列を見つけ、オフセットと長さを持つ文字列への参照を使用することによって部分的に圧縮します。したがって、どの時点でも、その時点から圧縮解除できるかどうかは、最後の 32K に依存し、それ自体はその前の 32K に依存し、というように先頭に戻ります。したがって、ストリーム内の任意のポイントxでデータを解凍するには、最初に0からx-1までのすべてを解凍する必要があります。

この状況を緩和する方法はいくつかあります。まず、gzip ファイルに頻繁にランダムにアクセスしたい場合は、gzip ファイル全体を一度スキャンしてインデックスを作成する作業を進んで行うでしょう。インデックスには、いくつかのエントリ ポイントのそれぞれで保存された以前の 32K が含まれます。これらのエントリ ポイントの密度によって、ランダム アクセスの速度が決まります。zlib ソース配布では、 examples/zran.cでこの例を見ることができます。

gzip ファイルの生成を管理している場合は、Z_FULL_FLUSHflush オプションを使用して、それらの時点で最後の 32K の履歴を定期的に消去し、ランダム アクセス エントリを許可することができます。次に、それらのポイントの場所をインデックスとして保存します。これにより、各エントリ ポイントに 32K ブロックの履歴が必要なくなります。これらのポイントが十分にまれである場合、圧縮への影響はほとんどありません。

Z_FULL_FLUSHgzip 出力を書き込めるだけで、連結された gzip ストリームを書き出すだけで、わずかに多くのオーバーヘッドで 同様のことができます。gunzipコマンドでまとめられた gzip ストリームを受け入れてデコードしcat、圧縮されていないデータの単一のストリームを書き出します。この方法で大きな gzip ログを作成でき、各 gzip 部分の開始位置のオフセットを記憶できます。

末尾のみに関心がある場合は、コメントの 1 つで提案されていることを実行できます。これは、大きな gzip ファイルの末尾の別の場所にキャッシュを維持するだけです。

ログファイルを作成しているかどうかはわかりません。もしそうなら、大きな gzip ファイルに短いログ メッセージを効率的に追加する例を見たいと思うかもしれません。これは、zlib ソース ディストリビューションにも見られます。

于 2012-10-06T17:10:50.517 に答える
6

gzip ファイルはストリームであるため、最終行まで読む必要があります。

from gzip import GzipFile
from collections import deque
dq = deque(maxlen=1)
with GzipFile('firewall.4.gz') as file:
    head = next(file)
    dq.extend(file)
tail = dq[0]
于 2012-10-06T16:28:17.507 に答える
5

そうする方法はありません。DEFLATE はストリーム圧縮アルゴリズムです。つまり、ファイルの任意の部分を解凍するには、その前のすべてを解凍する必要があります。

于 2012-10-06T16:20:42.040 に答える