稀疏文件:如何查找内容

时间:2017-09-07 16:07:21

标签: python unix sparse-file

如果我创建一个文件,使用lseek(2)跳转到(空)文件中的高位,然后在那里写一些有价值的信息,我在Unix系统上创建一个稀疏文件(可能取决于文件系统)我使用过,但是我们假设我使用的是典型的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()

这将创建一个只使用8k磁盘空间的2TB文件:

$ du -h sparse 
8.0K    sparse

在它的中间某处(1TB + 42字节)是有价值的信息(foo)。

我当然可以使用cat sparse找到它,但是这将读取完整的文件并打印大量的零字节。我尝试使用较小的尺寸,发现这种方法需要大约3小时才能在我的电脑上打印三个字符。

问题是:

有没有办法在不读取所有空块的情况下查找存储在稀疏文件中的信息?我可以使用标准的Unix方法以某种方式找出稀疏文件中空块的位置吗?

1 个答案:

答案 0 :(得分:1)

只需根据先前的评论写出答案:

#!/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()

但是,它可能并没有满足您的要求,而这恰恰返回了您编写的数据。零可能会包围返回的数据,因此必须手动进行修剪。

https://man7.org/linux/man-pages/man2/lseek.2.html中描述了SEEK_DATA和SEEK_HOLE的当前状态:

SEEK_DATA和SEEK_HOLE是Solaris,FreeBSD和DragonFly BSD中也存在的非标准扩展;建议将它们包含在下一个POSIX修订版中(问题8)。