2017-01-24 12 views
0

А есть файл, который может быть прочитан с помощью Fortran, и производит следующий вывод:Чтения FORtran двоичных данных с питоном, поплавки и Интс

0  2044150  229424   0   0   0 
0.0000000000000000  0.0000000000000000  
2.97821895219385624E-003 0.0000000000000000  0.0000000000000000   
0.0000000000000000  7.81250000000000000E-003 127.00000000000000    0   0   0 91948296 10067568  7115688   0 
0   0   48 67.769999999999996  
0.30700001120567322  0.69300001859664917  0.67769998311996460 

В принципе некоторых Int * 4 значений и некоторый поплавок * 8 значений (в заголовке). Я хочу, чтобы читать этот файл данных с помощью python. Я использовал следующий код:

f = open(fname,'rb') 
data = np.fromfile(file=f,dtype=np.int32) 
print data 

и я получаю результат:

[  256   0 2044150  229424   0   0 
     0   0   0   0   0 536870912 
1063806407   0   0   0   0   0 
     0   0 ] 

Некоторые из чисел в порядке, и я считаю, что 256 относится к размеру записи. Однако, когда я пытаюсь читать в поплавках (путем изменения np.int32 к np.float64) Я получаю

[ 1.26480805e-321 4.86836763e-309 0.00000000e+000 0.00000000e+000 
    0.00000000e+000 1.49166815e-154 5.25590200e-315  0.00000000e+000 
    0.00000000e+000 0.00000000e+000 5.26354425e-315 5.33599245e-315 
    0.00000000e+000 9.12063001e-306 3.51561699e-317 0.00000000e+000 
    -1.02951130e-086 2.68156223e+154 2.68156222e+154 -2.68156222e+154] 

что явно неправильно не только для int32s, но и для поплавка 64s я пытался читать.

Я подумал, что, возможно, это было связано с большим/littlendian, но не нашли исправления. Я также уверен, что я пытаюсь прочитать правильный тип данных (float64) и попробовал много других, и они создают похожие (или худшие) результаты.

Я знаю, что формат заголовка int * 4 (6), real * 8 (6), real * 8, real * 8, int * 4, int * 4, int * 4 (6) , int * 4, int * 4, real * 8, real * 8, real * 8, real * 8, character (96)

+3

вы не можете прочитать смешанный формат файла, указав либо INT или поплавок. Вы должны выбрать. Может быть, вы можете попробовать с 'struct.unpack' –

+0

С предыдущими файлами я открыл их дважды, используя fromfile с dtype = int один раз, затем повторно открыл тот же файл и использовал fromfile с dtype = float и ранее работал нормально. Моя причина для постановки вопроса заключается в том, что это как-то необъяснимо отличалось. – Jack

+0

проблема состоит в том, что файл начинается с 7 4-байтовых целых чисел. (Подсчет заголовка). Нечетно вы не выровнены правильно, если вы просто прочитали все это как 8 байтовых значений. – agentp

ответ

0

В файле данных отсутствует структура. Сначала вы должны знать, что находится в файле, а затем выбрать стратегию чтения, иначе вы будете читать цифры, но не будете знать, что они означают. Как пишет Jean-François Fabre, loadtxt не может справиться с вашей ситуацией, вам придется закодировать логику для файла самостоятельно. Вы можете делегировать разбор числовых частей на часть loadtxt, используя StringIO, например, https://docs.python.org/2/library/stringio.html#module-StringIO

+0

Возможно, вы упустили тот факт, что данные двоичные? –

0

В конце я использовал метод struct.unpack, предложенный выше. Мой код выглядит примерно так:

def read_block(start,data_format,data): 

    p = start # Count block size 

    # Read record size 
    rf = 'i' 
    rs = struct.calcsize(rf) 
    record = struct.unpack(rf,data[p:p+rs]) 
    p += rs 

    bs = record[0] 
    body = list(struct.unpack(data_format,data[p:p+bs])) 
    p += bs 

    p += rs # Record size again 

    return body,p-start 


''' Read specific file architecture ''' 
''' Easily modified ''' 
def read_gadget(gdt_file): 

    p = 0 

    with open(gdt_file,'rb') as binary_file: 
     data = binary_file.read() 


    header_fmt = '=6i8d10i4d96s'  
    header,header_size = read_block(p,header_fmt,data) 
    npart = header[:6] 
    mpart = header[6:12] 
    npart_tot = sum(npart) 
    p += header_size 


    pos_fmt = str(3*npart_tot)+'f' 
    pos_list,pos_size = read_block(p,pos_fmt,data) 
    pos_arr = np.zeros((npart_tot,3)) 
    for i in range(3): 
     pos_arr[:,i] = np.array(pos_list)[i*npart_tot:(i+1)*npart_tot] 
    p += pos_size 


    vel_fmt = str(3*npart_tot)+'f' 
    vel_list,vel_size = read_block(p,vel_fmt,data) 
    vel_arr = np.zeros((npart_tot,3)) 
    for i in range(3): 
     vel_arr[:,i] = np.array(vel_list)[i*npart_tot:(i+1)*npart_tot] 
    p += vel_size 

    id_fmt = str(npart_tot)+'l' 
    id_list,id_size = read_block(p,id_fmt,data) 
    p += id_size 
    id_arr = np.array(id_list) 


    mass_arr = np.array([]) 
    for i in range(6): 
     if npart[i]==0: 
      pass 
     elif npart[i]!=0 and mpart[i]==0: 
      mass_fmt = str(npart[i])+'f' 
      mass_list,mass_size = read_block(p,mass_fmt,data) 
      p += mass_size 
      mass_arr = np.append(mass_arr,np.array(mass_list)) 
     elif npart[i]!=0 and mpart[i]!=0: 
      mass_list = npart[i]*[mpart[i]] 
      mass_arr = np.append(mass_arr,np.array(mass_list)) 


    return header,pos_arr,vel_arr,id_arr,mass_arr 
+0

Поскольку вы знаете структуру, вы можете просто выполнить последовательность вызовов «np.fromfile», используя третий аргумент, чтобы указать количество элементов каждого типа для чтения. – agentp