Как читать и извлекать значения из двоичного файла с помощью кода Python?

Я относительно новичок в питоне. В рамках работы над моим астрономическим проектом мне приходится иметь дело с бинарными файлами (что, конечно, опять же для меня в новинку). Мне дали бинарный файл и код Python, который считывает данные из бинарного файла. Затем мой профессор попросил меня понять, как код работает с двоичным файлом. Пару дней пытался разобраться, но ничего не помогло. Может ли кто-нибудь здесь помочь мне с кодом?

# Read the binary opacity file
f = open(file, "r")

# read file dimension sizes
a = np.fromfile(f, dtype=np.int32, count=16)
NX, NY, NZ = a[1], a[4], a[7]


# read the time and time step
time, time_step = np.fromfile(f, dtype=np.float64, count=2)

# number of iterations
nite = np.fromfile(f, dtype=np.int32, count=1)

# radius array
trash = np.fromfile(f, dtype=np.float64, count=1)
rad = np.fromfile(f, dtype=np.float64, count=a[1])

# phi array
trash = np.fromfile(f, dtype=np.float64, count=1)
phi = np.fromfile(f, dtype=np.float64, count=a[4])

# close the file
f.close()

Бинарный файл, насколько мне известно, содержит несколько параметров (например: радиус, фи, скорость звука, энергия излучения) и множество его значений. Приведенный выше код извлекает значения 2 параметров — радиуса и фи из двоичного файла. И радиус, и фи имеют более 100 значений. Программа работает, но я не могу понять, как она работает. Любая помощь будет оценена по достоинству.


person manubjayan    schedule 19.05.2019    source источник
comment
Что именно вам не понятно?   -  person mkrieger1    schedule 19.05.2019
comment
Кроме того, поскольку большинство строк являются вызовами np.fromfile(), просмотрели ли вы его документация?   -  person Asmus    schedule 19.05.2019
comment
@Asmus Да, я сделал, но ничего не помогло   -  person manubjayan    schedule 19.05.2019
comment
@ mkrieger1 mkrieger1 Я не понимаю, как код получает значение из двоичного файла. Например, рассмотрим 2 строки ниже массива #radius. Как эти строки получают значение радиуса из двоичного файла?   -  person manubjayan    schedule 19.05.2019
comment
Привет, одна вещь, которую я понял при работе с двоичным файлом, это то, что порядок/последовательность, в которой объявляются данные, имеет значение. Например, в приведенной выше программе, если 'b' был вызван (используя np.fromfile) до 'a', тогда значения обмениваются, т. е. результат, который фактически отображался при вызове 'a', теперь отображается при вызове ' б'. Я правильно это понял?   -  person manubjayan    schedule 22.05.2019


Ответы (2)


Бинарный файл — это просто длинный список непрерывных данных; вам нужно указать np.fromfile() как где искать, так и какой тип данных ожидать. Возможно, проще всего будет понять, если вы создадите свой собственный файл:

import numpy as np

with open('numpy_testfile', 'w+') as f:
    ## we create a "header" line, which collects the lengths of all relevant arrays
    ## you can then use this header line to tell np.fromfile() *how long* the arrays are
    dimensions=np.array([0,10,0,0,10,0,3,10],dtype=np.int32)
    dimensions.tofile(f) ## write to file

    a=np.arange(0,10,1) ## some fake data, length 10
    a.tofile(f) ## write to file
    print(a.dtype)

    b=np.arange(30,40,1) ## more fake data, length 10
    b.tofile(f) ## write to file
    print(b.dtype)

    ##  more interesting data, this time it's of type float, length 3
    c=np.array([3.14,4.22,55.0],dtype=np.float64) 
    c.tofile(f) ## write to file
    print(c.dtype)

    a.tofile(f) ## just for fun, let's write "a" again

with open('numpy_testfile', 'r+b') as f:
    ### what's important to know about this step is that 
    #   numpy is "seeking" the file automatically, i.e. it is considering 
    #   the first count=8, than the next count=10, and so on 
    #   as "continuous data"
    dim=np.fromfile(f,dtype=np.int32,count=8)
    print(dim) ## our header line: [ 0 10  0  0 10  0  3 10]
    a=np.fromfile(f,dtype=np.int64,count=dim[1])## read the dim[1]=10 numbers
    b=np.fromfile(f,dtype=np.int64,count=dim[4])## and the next 10
    ## now it's dim[6]=3, and the dtype is float 10
    c=np.fromfile(f,dtype=np.float64,count=dim[6] )#count=30)
    ## read "the rest", unspecified length, let's hope it's all int64 actually!
    d=np.fromfile(f,dtype=np.int64) 

print(a)
print(b)
print(c)
print(d)

Дополнение: документация numpy довольно явно указывает на препятствование использованию np.tofile() и np.fromfile():

Не полагайтесь на комбинацию tofile и fromfile для хранения данных, так как сгенерированные бинарные файлы не зависят от платформы. В частности, информация о порядке байтов или типе данных не сохраняется. Данные можно хранить в независимом от платформы формате .npy, используя вместо этого функцию сохранения и загрузки.

Личное примечание: если вы потратили пару дней на то, чтобы понять этот код, не расстраивайтесь из-за изучения python; мы все с чего-то начинаем. Я бы посоветовал честно рассказать о препятствиях, с которыми вы столкнулись, своему профессору (если это всплывет в разговоре), поскольку он / она должен быть в состоянии правильно утверждать, «где вы находитесь», когда дело доходит до программирования. :-)

person Asmus    schedule 19.05.2019
comment
Большое вам спасибо за вашу помощь. Я буду иметь в виду, что вы сказали. Еще одна помощь, что означает эта строка, начинающаяся с мусора = ... в коде, который я разместил? - person manubjayan; 19.05.2019
comment
@manubjayan ну, я полагаю, это означает, что это буквальный мусор, то есть нерелевантная, ненужная информация, которую можно пропустить/игнорировать. Вам все еще нужно применить np.fromfile(.. count=1), чтобы искать/продвигаться на единицу. - person Asmus; 19.05.2019
comment
Привет, одна вещь, которую я понял при работе с двоичным файлом, это то, что порядок/последовательность, в которой объявляются данные, имеет значение. Например, в приведенной выше программе, если 'b' был вызван (используя np.fromfile) до 'a', тогда значения обмениваются, т. е. результат, который фактически отображался при вызове 'a', теперь отображается при вызове ' б'. Я правильно это понял? - person manubjayan; 22.05.2019
comment
@manubjayan да, это правильно, но это будет работать правильно, только если и a, и b имеют одинаковую длину и dtype. Рассмотрим строку: aaabbbccdddde; если бы я попросил вас написать инструкцию, как разделить эту строку по буквам, вы, скорее всего, получили бы такое утверждение, как первые три — это a, следующие три — b, следующие два — c, …. По сути, это то, что делает приведенный выше код, только если я скажу вам, что aaa следует понимать как один непрерывный элемент A, ваша инструкция должна измениться на первую one A, следующие три b,… (это то, что делает вывод dtype) - person Asmus; 22.05.2019

from astropy.io import ascii    
data = ascii.read('/directory/filename')
column1data = data[nameofcolumn1]
column2data = data[nameofcolumn2]

ЭСТ. column1data теперь представляет собой массив всех значений в этом заголовке. Я использую этот метод для импорта файлов данных SourceExtractor в формате ASCII. Я считаю, что это более элегантный способ импорта данных из файлов ascii.

person theastronomist    schedule 05.07.2019