Читання двійкового файлу з python


104

Мені дуже складно читати двійковий файл із Python. Ви можете мені подати руку? Мені потрібно прочитати цей файл, який у Fortran 90 легко читається

int*4 n_particles, n_groups
real*4 group_id(n_particles)
read (*) n_particles, n_groups
read (*) (group_id(j),j=1,n_particles)

Детально формат файлу:

Bytes 1-4 -- The integer 8.
Bytes 5-8 -- The number of particles, N.
Bytes 9-12 -- The number of groups.
Bytes 13-16 -- The integer 8.
Bytes 17-20 -- The integer 4*N.
Next many bytes -- The group ID numbers for all the particles.
Last 4 bytes -- The integer 4*N. 

Як я можу прочитати це за допомогою Python? Я спробував все, але ніколи не вийшло. Чи є можливість скористатися програмою f90 в python, прочитавши цей двійковий файл, а потім зберегти дані, які мені потрібно використовувати?


1
Чи був цей файл написаний програмою Fortran? Якщо так, як це було написано, оскільки за замовчуванням Fortran додає додаткові дані перед кожним записом, який він записує у файл. Можливо, вам доведеться подбати про це, читаючи дані.
Кріс

1
Будь ласка, ігноруйте мій попередній коментар, інтергери 8 і 4 * N - це явно ці додаткові дані.
Кріс

2
Також дивіться відповіді на питання читання двійкового файлу в python .
Кріс

Функція Numpy fromfileдозволяє легко читати бінарні файли. Рекомендую.
маленькийО

... і завжди слідкуйте за своїми ендіанцями, особливо. при перенесенні між різними комп'ютерами виробника.
DragonLord

Відповіді:


155

Прочитайте вміст бінарних файлів таким чином:

with open(fileName, mode='rb') as file: # b is important -> binary
    fileContent = file.read()

потім "розпакуйте" двійкові дані за допомогою struct.unpack :

Початкові байти: struct.unpack("iiiii", fileContent[:20])

Тіло: ігноруйте байти заголовка та байт із заднім числом (= 24); Решта частина утворює тіло, щоб знати кількість байтів у тілі, зробіть ціле ділення на 4; Отриманий коефіцієнт множимо на рядок, 'i'щоб створити правильний формат методу розпакування:

struct.unpack("i" * ((len(fileContent) -24) // 4), fileContent[20:-4])

Кінцевий байт: struct.unpack("i", fileContent[-4:])


Чи можете ви, будь ласка, подивитись на цю іншу посаду? stackoverflow.com/questions/8092469/… ... Я знову читаю ще один бінарний файл, але в цьому випадку детально не знаю структури байтів. Наприклад, я зрозумів, що іноді існує ціле число 8. Однак з IDL читати ці дані дуже просто. Чи можу я зробити те ж саме з python?
Брайан

Будь ласка, вкажіть (усередині іншої публікації, не тут), чому ви не задоволені опублікованими відповідями та коментарями. Можливо, вам слід також оновити питання, щоб надати більш детальну інформацію ... Я перегляну його, коли воно буде оновлено.
gecco

Дивіться цю відповідь, якщо вам потрібно перетворити розпакований char [] у рядок.
PeterM

import struct
JW

23

Загалом, я б рекомендував вивчити використання для цього модуля структури Python . Це стандартно для Python, і його слід легко перекласти специфікацією вашого запиту в формат для форматування, який підходить для struct.unpack().

Зауважте, що якщо між / навколо полів є "невидима" прокладка, вам потрібно буде це зрозуміти і включити його у unpack()виклик, або ви прочитаєте неправильні біти.

Читання вмісту файлу, щоб розпакувати щось досить тривіально:

import struct

data = open("from_fortran.bin", "rb").read()

(eight, N) = struct.unpack("@II", data)

Це розпаковує перші два поля, припускаючи, що вони починаються на самому початку файлу (без прокладки або сторонніх даних), а також припускаючи нативний порядок байтів ( @символ). В Iи в рядку форматування означає «ціле число без знака, 32 біта».


ОК, але я навіть не знаю, як читати байти файлу. З мого запитання, як я можу прочитати файл з байтів 5 до 8, а потім перетворити результат у ціле число? Вибачте, але я новачок у Python.
Брайан

14

Ви можете використовувати numpy.fromfile, які можуть читати дані як з текстових, так і з двійкових файлів. Ви спочатку побудуєте тип даних, який представляє ваш формат файлу, використовуючи numpy.dtype, а потім читайте цей тип із файлу за допомогою numpy.fromfile.


2
Легко пропустити це! Документи трохи тонкі; дивіться reddit.com/r/Python/comments/19q8nt/… для деякої дискусії
програв

11

Щоб прочитати бінарний файл bytesоб'єкту:

from pathlib import Path
data = Path('/path/to/file').read_bytes()  # Python 3.5+

Щоб створити intз байтів 0-3 даних:

i = int.from_bytes(data[:4], byteorder='little', signed=False)

Щоб розпакувати кілька intданих із даних:

import struct
ints = struct.unpack('iiii', data[:16])

0

Я також виявив, що Python не вистачає, коли мова йде про читання та запис бінарних файлів, тому я написав невеликий модуль (для Python 3.6+).

З бінарним файлом ви зробите щось подібне (гадаю, оскільки я не знаю Фортран):

import binaryfile

def particle_file(f):
    f.array('group_ids')  # Declare group_ids to be an array (so we can use it in a loop)
    f.skip(4)  # Bytes 1-4
    num_particles = f.count('num_particles', 'group_ids', 4)  # Bytes 5-8
    f.int('num_groups', 4)  # Bytes 9-12
    f.skip(8)  # Bytes 13-20
    for i in range(num_particles):
        f.struct('group_ids', '>f')  # 4 bytes x num_particles
    f.skip(4)

with open('myfile.bin', 'rb') as fh:
    result = binaryfile.read(fh, particle_file)
print(result)

Що дає такий результат:

{
    'group_ids': [(1.0,), (0.0,), (2.0,), (0.0,), (1.0,)],
    '__skipped': [b'\x00\x00\x00\x08', b'\x00\x00\x00\x08\x00\x00\x00\x14', b'\x00\x00\x00\x14'],
    'num_particles': 5,
    'num_groups': 3
}

Я використовував skip (), щоб пропустити додаткові дані, які додає Fortran, але ви можете замість цього додати утиліту для належної обробки записів Fortran. Якщо це зробити, запрошення на притягнення буде вітатися.


-2
import pickle
f=open("filename.dat","rb")
try:
    while True:
        x=pickle.load(f)
        print x
except EOFError:
    pass
f.close()

7
Напевно, варто лише трохи пояснити, чому це краще, ніж (або принаймні так добре, як) інші відповіді.
Філ

2
Ви перевірили, чи перевірено це, що працює з двійковою формою, створеною фортраном?
agentp

1
А також поясніть, що це робить ... Що таке соління? Що pickle.loadзавантажує? Чи завантажує він потік Fortran, прямі чи послідовні файли? Вони різні і не сумісні.
Володимир F
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.