ファイル圧縮率の推定

ファイル圧縮率の推定

gzipファイルを完全に圧縮せずにファイルの圧縮可能性を推定するための迅速で汚い方法はありますかgzip

俺はできて、できるよbash、できるよ

bc <<<"scale=2;$(gzip -c file | wc -c)/$(wc -c <file)"

gzこれにより、ファイルをディスクに書き込むことなく圧縮要素を取得できます。これにより、gzディスク領域の節約効果が面倒を正当化するのに十分でない場合、ディスク上のファイルをそのバージョンに置き換えることを回避できます。ただし、このアプローチではファイルが完全に渡されますgzip。これは、出力がディスクwcに書き込まれるのではなく、パイプに渡されることです。

gzipファイルの内容全体を処理せずにファイルのおおよその圧縮推定値を取得する方法はありますか?

答え1

以下は(おそらく同等の)Pythonバージョンです。スティーブン・チャジェラス 解決策

python -c "
import zlib
from itertools import islice
from functools import partial
import sys
with open(sys.argv[1], "rb") as f:
  compressor = zlib.compressobj()
  t, z = 0, 0.0
  for chunk in islice(iter(partial(f.read, 4096), b''), 0, None, 10):
    t += len(chunk)
    z += len(compressor.compress(chunk))
  z += len(compressor.flush())
  print(z/t)
" file

答え2

たとえば、10ブロックごとに圧縮してアイデアを得ることができます。

perl -MIPC::Open2 -nE 'BEGIN{$/=\4096;open2(\*I,\*O,"gzip|wc -c")}
                       if ($. % 10 == 1) {print O $_; $l+=length}
                       END{close O; $c = <I>; say $c/$l}'

(ここでは4Kブロック)。

答え3

複数のGBサイズのファイルがありますが、圧縮されたかどうかわからず、最初の10Mバイトを圧縮してテストしました。

head -c 10000000 large_file.bin | gzip | wc -c

完璧ではありませんが、私にとってはうまくいきます。

答え4

これはiruvarベースの改良されたPythonバージョンです。優れたソリューション。主な改善点は、スクリプトが実際に圧縮したディスクのデータブロックのみを読み取ることです。

import zlib
def Predict_file_compression_ratio(MyFilePath):
 blocksize = (4096 * 1) # Increase if you want to read more bytes per block at once.
 blocksize_seek = 0

 # r = read, b = binary
 with open(MyFilePath, "rb") as f:
  # Make a zlib compressor object, and set compression level.
  # 1 is fastest, 9 is slowest
  compressor = zlib.compressobj(1)
  t, z, counter = 0, 0, 0

  while True:
    # Use this modulo calculation to check every "number" of blocks.
    if counter % 10 == 0:
      # Seek to the correct byte position of the file.
      f.seek(blocksize_seek)
      # The block above will be read, increase the seek distance by one block for the next iteration.
      blocksize_seek += blocksize
      # Read data chunk of file into this variable.
      data = f.read(blocksize)
      
      # Stop if there are no more data.
      if not data:
        # For zlib: Flush any remaining compressed data. Not doing this can lead to a tiny inaccuracy.
        z += len(compressor.flush())
        break

      # Uncompressed data size, add size to variable to get a total value.
      t += len(data)
      # Compressed data size
      z += len(compressor.compress(data))

    # When we skip, we want to increase the seek distance. This is vital for correct skipping.
    else:
      blocksize_seek += blocksize
    # Increase the block / iteration counter.
    counter += 1

 # Print the results. But avoid division by 0 >_>
 if not t == 0:
  print('Compression ratio: ' + str(z/t))
 else:
  print('Compression ratio: none, file has no content.')
 print('Compressed: ' + str(z))
 print('Uncompressed: ' + str(t))

高いデータレートが重要で、正確な圧縮率がそれほど重要ではない場合は、lz4を使用できます。これは、低CPU使用率で最も圧縮可能なファイルを見つけたい場合に便利です。このモジュールはpipを使用してインストールする必要があります。ここから。 Pythonコード自体ではこれが必要なすべてです。

import lz4.block
z += len(lz4.block.compress(data))

このスクリプトを使用すると、余分なメモリが破壊され(確かにWindowsで)ファイルのパフォーマンスが低下する可能性があることを観察しました。特に、既存のハードドライブがあるシステムで、かつ一度に多数のファイルでこの機能を使用する場合は、さらにそうです。スクリプトのPythonプロセスで低メモリページの優先順位を設定すると、これらのメモリの無駄を回避できます。私はこの作業のためにWindowsでAutoHotkeyを使用することにしました。便利なソースここ

関連情報