Here is an improved Python version based on iruvar's awesome solution. The main improvement is that the script reads only the data blocks from disk that it actually compresses:
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))
If high data rates are crucial and accurate compression ratios not so much, you can use lz4 instead. It's great if you only want to find out what files can be compressed the most, with low CPU usage. This module needs to be installed with pip from here. In the Python code itself, you pretty much only need this:
import lz4.block
z += len(lz4.block.compress(data))
Please note, I observed that using this script does thrash the standby memory (does for sure on Windows), which degrades file performance - especially on computers with classic hard drives, and if you use this function for lots of files at once. This memory trashing can be avoided by setting a low memory page priority on the script's Python process. I opted to do this with AutoHotkey on Windows. Helpful source here.