|
158 |
try: |
158 |
try: |
159 |
with contextlib.nested(open(infile, 'rb'), open(outfile, 'wb')) as (fin, fout): |
159 |
with contextlib.nested(open(infile, 'rb'), open(outfile, 'wb')) as (fin, fout): |
160 |
counter = 0 |
160 |
counter = 0 |
|
|
161 |
BLOCK_SIZE = 4096 # block size is dependent on file system block size for sparse file |
161 |
while True: |
162 |
while True: |
162 |
compressed_data = fin.read(DEFAULT_CHUNK_SIZE) |
163 |
compressed_data = fin.read(DEFAULT_CHUNK_SIZE) |
163 |
if not compressed_data: |
164 |
if not compressed_data: |
|
165 |
break |
166 |
break |
166 |
|
167 |
|
167 |
uncompressed_data = decompressor.decompress(compressed_data) |
168 |
uncompressed_data = decompressor.decompress(compressed_data) |
168 |
fout.write(uncompressed_data) |
169 |
|
|
|
170 |
# don't write blocks that consist only of 0-bytes to keep sparse file format |
171 |
for i in xrange(0, len(uncompressed_data), BLOCK_SIZE): |
172 |
if len(uncompressed_data[i:i+BLOCK_SIZE]) == BLOCK_SIZE: |
173 |
if uncompressed_data[i:i+BLOCK_SIZE].count('\x00') == BLOCK_SIZE: |
174 |
fout.seek(BLOCK_SIZE, os.SEEK_CUR) |
175 |
else: |
176 |
fout.write(uncompressed_data[i:i+BLOCK_SIZE]) |
177 |
# decompressed data can not be always a multiple of BLOCK_SIZE |
178 |
# so write rest data to avoid data loss |
179 |
else: |
180 |
fout.write(uncompressed_data[i:]) |
181 |
|
169 |
progress(fin.tell(), total_size) |
182 |
progress(fin.tell(), total_size) |
170 |
del compressed_data |
|
|
171 |
del uncompressed_data |
172 |
|
183 |
|
173 |
# check free size on disk every N rounds |
184 |
# check free size on disk every N rounds |
174 |
if counter % 50 == 0: |
185 |
if counter % 50 == 0: |