我有一个 50 GB 的 zip 文件,其中包含大约 50,000 张 jpg 图像。这些 jpg 图像解压后大约有 55 GB。我使用的是 Ubuntu 16.04。
但是我的系统上只有 70 GB 的磁盘大小。因此在解压过程中出现了磁盘错误。
我可以解压该文件,并同时减小 zip 文件的大小(例如,删除已经解压的 jpg 数据),以便所有内容都可以放在我的磁盘上吗?
--- Windows 上也存在同样的问题 ---
有人对 Windows 有完全相同的问题:在小驱动器上解压文件
不幸的是,那里提出的解决方案无法解决我在 Linux 上的问题(而且似乎也无法很好地解决 Windows 上的问题)。所以我保留了这个问题,以防有针对 Linux 的好的解决方案。感谢您的评论。
答案1
答案2
您可以尝试利用 Linux 特定的系统调用谬误或命令行等效项。此FALLOC_FL_PUNCH_HOLE
模式允许您将文件的任何给定部分清零,并在可能的情况下将受影响的块释放回文件系统,从而疏文件。
并非所有文件系统都支持此调用,但 ext4 支持。
其思路是从存档中提取文件,然后使用 fallocate 将其占用的存档部分清零。zip 存档的字典保存了每个文件头开头的偏移量,以及存档内文件的压缩长度。
作为概念的一个示例,这里有一个最小的 Python3 脚本,用于提取每个文件并执行系统调用。未经仔细测试,请勿使用它。如果您可以提取信息,您可能可以在 shell 脚本中执行相同操作。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