How to read bytes from file

Refresh

November 2018

Views

3.8k time

3

I'm trying to read the length of some metadata from a .lrf file. (Used with the program LoLReplay)

There's not really documentation on these files, but I have already figured out how to do this in C++. I'm trying to re-write the project in python for multiple reasons, but I come across an error.

To first explain, the .lrf file has metadata immediately at the start of the file in this format:

  • first 4 bytes are for something I have no clue about.

  • next 4 bytes store the length of the metadata in hexidecimal, up until the end of the metadata, which after is the actual contents of the replay.

  • bytes after the initial 8 bytes are the metadata in json format

The problem I'm having is actually reading the metadata length. This is the current function I have:

def getMetaLength(self):
    try:
        file = open(self.file,"r")
    except IOError:
        print ("Failed to open file.")
        file.close()
    #We need to skip the first 4 bytes.
    file.read(4)
    mdlength = file.read(4)
    print(hex(mdlength))
    file.close()

When I call this function, the shell returns a traceback stating:

    Traceback (most recent call last):
    File "C:\Users\Donald\python\lolcogs\lolcogs_main.py", line 6, in <module>
    lolcogs.getMetaLength()
    File "C:\Users\Donald\python\lolcogs\LoLCogs.py", line 20, in getMetaLength
    file.read(4)
    File "C:\Python32\lib\encodings\cp1252.py", line 23, in decode
    return codecs.charmap_decode(input,self.errors,decoding_table)[0]
    UnicodeDecodeError: 'charmap' codec can't decode byte 0x81 in position 3648:       character maps to <undefined>

My best guess is that read() is trying to read characters that are encoded in some unicode format, but these are definitely just bytes that I am attempting to read. Is there a way to read these as bytes? Also, is there a better way to skip bytes when you are attempting to read a file?

3 answers

1

Вы должны открыть файл в двоичном режиме: open(filename, 'rb').

2

В Python открыты 3 файла в текстовом режиме с кодировкой системы по умолчанию. Вам нужно открыть файл в двоичном режиме:

file = open(self.file, 'rb')

Еще одна проблема , вы столкнетесь в том , что file.read(4)даст вам строку 4 байта (которых hexфункция не понимает). И вы , возможно , хотите целое. Для этого, см int.from_bytes, или, в более общем плане , к STRUCT модуля . Затем вы можете распечатать это число в шестнадцатеричном формате, так:

mdlength = int.from_bytes(file.read(4), byteorder='big')
print(hex(mdlength))
2

Бинарные файлы должны быть обработаны в двоичном режиме:

f = open(filename, 'rb')

Для пропуска байт, я обычно использую файл seek(SEEK_CUR или SEEK_SET) или я просто произволен , file.read(n)если я не хочу возиться с формальностью. Только раз , когда я действительно использовать искание, если я хотел бы перейти к конкретной позиции.

Устный двоичные данные я просто прилипает к распаковке способом , предусмотренным в structмодуле, что позволяет легко определить , нужно ли интерпретировать последовательность байтов в качестве межд, поплавок, полукокса и т.д. Вот как я делал это в течение многих лет поэтому , возможно , есть более эффективные подходы , как from_bytesметода , описанная в других ответах.

С помощью модуля STRUCT вы можете сделать что-то вроде

struct.unpack("3I", f.read(12))

Для чтения в 3 (без знака) целых сразу. Так, например, данный формат вы обращенная инженерия, я бы, наверное, просто сказать,

unk, size = struct.unpack("2I", f.read(8))
data = f.read(size)