Alf*_*lfe 5 python unix sparse-file
如果我创建一个文件,用于lseek(2)跳到(空)文件中的较高位置,然后在其中写入一些有价值的信息,那么我会在Unix系统上创建一个稀疏文件(可能取决于我使用的文件系统,但是假设我m使用典型的Unix文件系统(例如ext4或类似文件),就是这种情况。
如果然后我lseek(2)在文件中甚至更高的位置上写一些东西,我最终会得到一个稀疏文件,该文件的中间位置包含有价值的信息,并被大量稀疏文件包围。我想在文件中找到这些有价值的信息,而不必完全阅读它。
例:
$ python
f = open('sparse', 'w')
f.seek((1<<40) + 42)
f.write('foo')
f.seek((1<<40) * 2)
f.write('\0')
f.close()
Run Code Online (Sandbox Code Playgroud)
这将创建一个仅使用8k磁盘空间的2TB文件:
$ du -h sparse
8.0K sparse
Run Code Online (Sandbox Code Playgroud)
中间的某处(1TB + 42字节)是有价值的信息(foo)。
我cat sparse当然可以找到它,但是它将读取完整的文件并输出大量的零字节。我尝试使用较小的尺寸,发现此方法大约需要3个小时才能在计算机上打印三个字符。
问题是:
有没有一种方法可以找到存储在稀疏文件中的信息,而无需同时读取所有空块?我可以使用标准的Unix方法以某种方式找出稀疏文件中的空块吗?
Just writing an answer based on the previous comments:
#!/usr/bin/env python3
from errno import ENXIO
from os import lseek
from sys import argv, stderr
SEEK_DATA = 3
SEEK_HOLE = 4
def get_ranges(fobj):
ranges = []
end = 0
while True:
try:
start = lseek(fobj.fileno(), end, SEEK_DATA)
end = lseek(fobj.fileno(), start, SEEK_HOLE)
ranges.append((start, end))
except OSError as e:
if e.errno == ENXIO:
return ranges
raise
def main():
if len(argv) < 2:
print('Usage: %s <sparse_file>' % argv[0], file=stderr)
raise SystemExit(1)
try:
with open(argv[1], 'rb') as f:
ranges = get_ranges(f)
for start, end in ranges:
print('[%d:%d]' % (start, end))
size = end-start
length = min(20, size)
f.seek(start)
data = f.read(length)
print(data)
except OSError as e:
print('Error:', e)
raise SystemExit(1)
if __name__ == '__main__': main()
Run Code Online (Sandbox Code Playgroud)
It probably doesn't do what you want, however, which is returning exactly the data you wrote. Zeroes may surround the returned data and must be trimmed by hand.
Current status of SEEK_DATA and SEEK_HOLE are described in https://man7.org/linux/man-pages/man2/lseek.2.html:
SEEK_DATA and SEEK_HOLE are nonstandard extensions also present in Solaris, FreeBSD, and DragonFly BSD; they are proposed for inclusion in the next POSIX revision (Issue 8).