Как читать в двоичных данных после заголовка ascii в Python - PullRequest
2 голосов
/ 05 февраля 2011

У меня есть некоторые данные изображений, которые хранятся в файле, который содержит текстовый заголовок ascii, заканчивающийся нулевым символом, за которым следуют двоичные данные.Заголовки ascii различаются по длине, и мне интересно, как лучше открыть файл, прочитать заголовок и найти нулевой символ, а затем загрузить двоичные данные (в Python).

Спасибо запомощь,
Джеймс

Ответы [ 3 ]

1 голос
/ 05 февраля 2011

Вероятно, следует начать с чего-то подобного.

with open('some file','rb') as input:
    aByte= input.read(1)
    while aByte and ord(aByte) != 0: aByte= input.read(1)
    # At this point, what's left is the binary data.

Номера версий Python очень важны для такого рода вещей.Проблема связана с функцией read.Некоторые версии могут возвращать байты (которые являются числами).Другие версии будут возвращать строки (для этого требуется ord(aByte)).

1 голос
/ 05 февраля 2011

Другие люди уже ответили на ваш вопрос о направлении, но я подумал, что добавлю это.

При работе с двоичными данными я часто нахожу полезным использовать подкласс file и добавлять различные методы убеждения для чтения/ запись упакованных двоичных данных.

Это просто излишне для простых вещей, но если вы обнаружите, что разбираете много двоичных форматов файлов, стоит потратить дополнительные усилия, чтобы избежать повторения.

Если ничего другого, надеюсь, это будет полезнымПример использования struct.На заметку, это взято из старого кода, и это очень много Python 2.x.Python 3.x обрабатывает это (особенно строки и байты) значительно по-разному.

import struct
import array

class BinaryFile(file):
    """
    Automatically packs or unpacks binary data according to a format
    when reading or writing.
    """
    def __init__(self, *args, **kwargs):
        """
        Initialization is the same as a normal file object
        %s""" % file.__doc__
        super(BinaryFile, self).__init__(self, *args, **kwargs)

    def read_binary(self,fmt):
        """
        Read and unpack a binary value from the file based
        on string fmt (see the struct module for details).
        This will strip any trailing null characters if a string format is
        specified. 
        """
        size = struct.calcsize(fmt)
        data = self.read(size)
        # Reading beyond the end of the file just returns ''
        if len(data) != size:
            raise EOFError('End of file reached')
        data = struct.unpack(fmt, data)

        for item in data:
            # Strip trailing zeros in strings 
            if isinstance(item, str):
                item = item.strip('\x00')

        # Unpack the tuple if it only has one value
        if len(data) == 1: 
            data = data[0]

        return data

    def write_binary(self, fmt, dat):
        """Pack and write data to the file according to string fmt."""
        # Try expanding input arguments (struct.pack won't take a tuple)
        try: 
            dat = struct.pack(fmt, *dat) 
        except (TypeError, struct.error): 
            # If it's not a sequence (TypeError), or if it's a 
            # string (struct.error), don't expand.
            dat = struct.pack(fmt, dat) 
        self.write(dat)

    def read_header(self, header):
        """
        Reads a defined structure "header" consisting of a sequence of (name,
        format) strings from the file. Returns a dict with keys of the given
        names and values unpaced according to the given format for each item in
        "header".
        """
        header_values = {}
        for key, format in header:
            header_values[key] = self.read_binary(format)
        return header_values

    def read_nullstring(self):
        """
        Reads a null-terminated string from the file. This is not implemented
        in an efficient manner for long strings!
        """
        output_string = ''
        char = self.read(1)
        while char != '\x00':
            output_string += char
            char = self.read(1)
            if len(char) == 0:
                break
        return output_string

    def read_array(self, type, number):
        """
        Read data from the file and return an array.array of the given
        "type" with "number" elements
        """
        size = struct.calcsize(type)
        data = self.read(size * number)
        return array.array(type, data)
1 голос
/ 05 февраля 2011

Делает что-то вроде этой работы:

with open('some_file','rb') as f:
  binary_data = f.read().split('\0',1)[1]
...