Вы можете попробовать воспользоваться системным вызовом, специфичным для Linux, fallocate или эквивалентом командной строки. FALLOC_FL_PUNCH_HOLE
Режим позволяет обнуление любой данной части файла, и, где это возможно затрагиваемые блоки высвобождаются обратно в файловую систему, делая разреженный файл.
Не все файловые системы поддерживают этот вызов, но ext4 поддерживает.
Идея состоит в том, что вы извлекаете файл из архива, а затем используете fallocate, чтобы обнулить часть архива, которую он занимал. Словарь zip-архива содержит смещение к началу заголовка каждого файла и сжатую длину файла в архиве.
В качестве примера концепции приведен минимальный скрипт Python3 для извлечения и выполнения системного вызова для каждого файла. Вы не должны использовать его без тщательного тестирования. Вы можете сделать то же самое в сценарии оболочки, если сможете извлечь информацию. Для меня fallocate не входил в стандартную библиотеку Python, поэтому в первой половине скрипта для ее вызова используется ctypes. Сценарию нужна библиотека Python Zipfile. Также могут потребоваться другие изменения для вашей системы. Сумма обнуления не включает размер заголовка, который не дает им стать одной смежной областью.
#!/usr/bin/python3 # https://superuser.com/a/1371106/458747 # int fallocate(int fd, int mode, off_t offset, off_t len) import ctypes libc = ctypes.cdll.LoadLibrary("libc.so.6") fallocate = libc.fallocate fallocate.argtypes = (ctypes.c_int, ctypes.c_int, ctypes.c_longlong, ctypes.c_longlong) FALLOC_FL_PUNCH_HOLE = 2 FALLOC_FL_KEEP_SIZE = 1 import sys, subprocess, zipfile # will need zlib for compression myzip = sys.argv[1] fd = open(myzip,"r+") fno = fd.fileno() zf = zipfile.ZipFile(myzip, 'r') for info in zf.infolist(): zf.extract(info) # print(info.header_offset,info.compress_size) rc = fallocate(fno, FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE, info.header_offset, info.compress_size) if rc!=0: print("fallocate failed\n") subprocess.call("ls -ls "+myzip,shell=True)
Я проверил его на простом zip-архиве, и в первом столбце вы можете увидеть количество блоков, используемых архивом, которое уменьшается по мере извлечения каждого файла:
24224 -rw-r--r-- 25562742 Oct 29 22:56 ../my.zip 23292 -rw-r--r-- 25562742 Oct 29 22:56 ../my.zip 22524 -rw-r--r-- 25562742 Oct 29 22:56 ../my.zip 21524 -rw-r--r-- 25562742 Oct 29 22:56 ../my.zip ... 2800 -rw-r--r-- 25562742 Oct 29 22:56 ../my.zip 1868 -rw-r--r-- 25562742 Oct 29 22:56 ../my.zip 880 -rw-r--r-- 25562742 Oct 29 22:56 ../my.zip 124 -rw-r--r-- 25562742 Oct 29 22:56 ../my.zip