Python 稀疏文件:如何查找内容

Python 稀疏文件:如何查找内容,python,unix,sparse-file,Python,Unix,Sparse File,如果我创建一个文件,使用lseek(2)跳转到(空)文件中的较高位置,然后在那里写入一些有价值的信息,我在Unix系统上创建一个稀疏文件(可能取决于我使用的文件系统,但假设我使用的是典型的Unix文件系统,如ext4或类似的系统,就是这样) 如果我然后lseek(2)到文件中更高的位置,也在那里写一些东西,我最终会得到一个稀疏文件,其中包含有价值的信息,周围是大量稀疏文件。我想在文件中找到这些有价值的信息,而不必完全阅读 例如: $ python f = open('sparse', 'w')

如果我创建一个文件,使用
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()

中的某个地方(在1Tb+ 42字节)是有价值的信息(<代码> Foo)。 当然,我可以使用

catsparse
找到它,但这将读取完整的文件并打印大量的零字节。我试着用较小的尺寸,发现这种方法在我的电脑上打印三个字符大约需要3小时

问题是:


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

根据前面的评论写一个答案:

#!/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()
#/usr/bin/env蟒蛇3
来自errno import ENXIO
从os导入lseek
从系统导入argv、stderr
搜索数据=3
寻道孔=4
def get_范围(fobj):
范围=[]
结束=0
尽管如此:
尝试:
start=lseek(fobj.fileno(),end,SEEK_数据)
end=lseek(fobj.fileno(),start,SEEK_-HOLE)
范围。追加((开始,结束))
除O错误为e外:
如果e.errno==ENXIO:
返回范围
提升
def main():
如果len(argv)<2:
打印('用法:%s'%argv[0],file=stderr)
升起系统出口(1)
尝试:
将open(argv[1],'rb')作为f:
范围=获取范围(f)
对于开始,在范围内结束:
打印('[%d:%d]'%(开始,结束))
大小=结束-开始
长度=最小值(20,尺寸)
f、 搜索(开始)
数据=f.read(长度)
打印(数据)
除O错误为e外:
打印('错误:',e)
升起系统出口(1)
如果uuuu name_uuuuuu=='uuuuuu main:main()
但是,它可能不会执行您想要的操作,即返回您编写的数据。返回的数据周围可能有零,必须手动修剪

SEEK_数据和SEEK_孔的当前状态如所述:

SEEK_数据和SEEK_洞是Solaris、FreeBSD和DragonFly BSD中也存在的非标准扩展;建议将其纳入下一个POSIX修订版(第8期)


它被称为稀疏文件而不是备用文件。@direprobs是的,谢谢。也多亏了那个家伙,已经有人修复了这个拼写错误。当标记还不知道时,我应该更加怀疑。稀疏文件的问题是,文件系统在运行时生成空字节,空字节也被假定为文件中的数据。即使您将
lseek(2)
SEEK\u数据一起使用,这也不起作用。因此,当您查找实际数据时,文件系统会将零视为实际数据,尽管从我们的角度来看,它们只是零。是的。问题是,有没有办法找出文件的稀疏部分和非稀疏部分在哪里?一些低级稀疏文件支持?请参阅
lseek(2)
中的第40行。我不知道一个技巧来消除稀疏零点,只在中间得到<代码> Foo。不幸的是,你的问题还没有得到应有的重视。这是基于旗帜的存在,但我想这是我们将得到的最接近的答案。在未来,它可能是标准的。
#!/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()