Как я могу обработать часть файла, как будто это сам файл?

У меня есть данные, хранящиеся в коллекции файлов или в одном составном файле. Составной файл формируется путем объединения всех отдельных файлов, а затем предшествует всему заголовку, в котором указаны смещения и размеры составных частей. Я хотел бы иметь подобный файлу объект, который представляет представление составного файла, где представление представляет только один из файлов участника. (Таким образом, у меня могут быть функции для чтения данных, которые принимают либо реальный файловый объект, либо объект "просмотра", и им не нужно беспокоиться о том, как хранится какой-либо конкретный набор данных.) Какая библиотека будет делать это для меня?

mmap класс выглядел многообещающе, так как он построен из файла, длины и смещения, и это именно то, что у меня есть, но смещение должно быть выровнено с гранулярностью выделения базовой файловой системы, а файлы, которые я читаю, не соответствуют это требование. Наименование MultiFile Класс отвечает всем требованиям, но он предназначен для вложений в сообщениях электронной почты, и мои файлы не имеют такой структуры.

Больше всего меня интересуют файловые операции read, seek, а также tell, Файлы, которые я читаю, являются двоичными, поэтому текстовые функции, такие как readline а также next не так важны. Я мог бы в конечном счете также нуждаться write, но я готов пока отказаться от этой функции, так как не знаю, как должен вести себя добавление.

2 ответа

Решение

Я знаю, что вы искали библиотеку, но как только я прочитал этот вопрос, я решил написать свою собственную. Итак, вот оно:

import os

class View:
    def __init__(self, f, offset, length):
        self.f = f
        self.f_offset = offset
        self.offset = 0
        self.length = length

    def seek(self, offset, whence=0):
        if whence == os.SEEK_SET:
            self.offset = offset
        elif whence == os.SEEK_CUR:
            self.offset += offset
        elif whence == os.SEEK_END:
            self.offset = self.length+offset
        else:
            # Other values of whence should raise an IOError
            return self.f.seek(offset, whence)
        return self.f.seek(self.offset+self.f_offset, os.SEEK_SET)

    def tell(self):
        return self.offset

    def read(self, size=-1):
        self.seek(self.offset)
        if size<0:
            size = self.length-self.offset
        size = max(0, min(size, self.length-self.offset))
        self.offset += size
        return self.f.read(size)

if __name__ == "__main__":
    f = open('test.txt', 'r')

    views = []
    offsets = [i*11 for i in range(10)]

    for o in offsets:
        f.seek(o+1)
        length = int(f.read(1))
        views.append(View(f, o+2, length))

    f.seek(0)

    completes = {}
    for v in views:
        completes[v.f_offset] = v.read()
        v.seek(0)

    import collections
    strs = collections.defaultdict(str)
    for i in range(3):
        for v in views:
            strs[v.f_offset] += v.read(3)
    strs = dict(strs) # We want it to raise KeyErrors after that.

    for offset, s in completes.iteritems():
        print offset, strs[offset], completes[offset]
        assert strs[offset] == completes[offset], "Something went wrong!"

И я написал другой скрипт для генерации файла "test.txt":

import string, random

f = open('test.txt', 'w')

for i in range(10):
    rand_list = list(string.ascii_letters)
    random.shuffle(rand_list)
    rand_str = "".join(rand_list[:9])
    f.write(".%d%s" % (len(rand_str), rand_str))

Это сработало для меня. Файлы, на которых я тестировал, не являются бинарными, как ваши, и они не такие большие, как ваши, но я надеюсь, что это может быть полезно. Если нет, то спасибо, это был хороший вызов:D

Кроме того, мне было интересно, если это на самом деле несколько файлов, почему бы не использовать какой-нибудь формат файла архива и использовать их библиотеки для их чтения?

Надеюсь, поможет.

В зависимости от того, насколько сложным вам это должно быть, что-то вроде этого должно работать - я остановился на некоторых деталях, поскольку не знаю, насколько близко вам нужно эмулировать файловый объект (например, будете ли вы когда-либо использовать obj.read(), или вы всегда будете использовать obj.read(nbytes)):

class FileView(object):
     def __init__(self,file,offset,length):
         self._file=file
         self._offset=offset
         self._length=length

     def seek(self,pos):
         #May need to get a little fancier here to support the second argument to seek.
         return self._file.seek(self._offset+pos)

     def tell(self):
         return self._file.tell()-self._offset

     def read(self,*args):
         #May need to get a little more complicated here to make sure that the number of
         #bytes read is smaller than the number of bytes available for this file
         return self._file.read(*args)
Другие вопросы по тегам