Python ile ikili dosya okumak


105

Python ile ikili dosyayı okumakta özellikle zorlanıyorum. Bana yardım edebilir misin? Fortran 90'da kolayca okunabilen bu dosyayı okumam gerekiyor

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)

Ayrıntılı olarak, dosya biçimi şöyledir:

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. 

Bunu Python ile nasıl okuyabilirim? Her şeyi denedim ama hiç işe yaramadı. Python'da bir f90 programı kullanıp bu ikili dosyayı okuyup daha sonra kullanmam gereken verileri kaydetme şansım var mı?


1
Bu dosya bir Fortran programı tarafından mı yazılmış? Eğer öyleyse, Fortran varsayılan olarak dosyaya yazdığı her kayıttan önce ek veri eklediği için nasıl yazılmıştır. Verileri okurken buna dikkat etmeniz gerekebilir.
Chris

1
Lütfen önceki yorumumu göz ardı edin, 8 ve 4 * N intergers açıkça bu ek verilerdir.
Chris

2
Ayrıca, python'da ikili dosya okuyan sorunun yanıtlarına bakın .
Chris

Numpy'nin fromfileişlevi, ikili dosyaları okumayı kolaylaştırır. Bunu öneririm.
littleO

... ve her zaman endian-lelerinize dikkat edin, özellikle. farklı üreticilerin bilgisayarları arasında taşıma yaparken.
DragonLord

Yanıtlar:


157

İkili dosya içeriğini şu şekilde okuyun:

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

daha sonra struct.unpack kullanarak ikili verileri "paketinden çıkarın" :

Başlangıç ​​baytları: struct.unpack("iiiii", fileContent[:20])

Gövde: başlık baytlarını ve sondaki baytı yok sayın (= 24); Kalan kısım gövdeyi oluşturur, vücuttaki bayt sayısını bilmek için 4'e bir tamsayı bölümü yapar; Elde edilen bölüm, paket 'i'açma yöntemi için doğru biçimi oluşturmak üzere dizeyle çarpılır :

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

Bitiş baytı: struct.unpack("i", fileContent[-4:])


Lütfen şu diğer gönderiye bakar mısınız? stackoverflow.com/questions/8092469/… ... Yine başka bir ikili dosya okuyacağım, ancak bu durumda bayt yapısını ayrıntılı olarak bilmiyorum. Örneğin, bazen 8 tamsayısının olduğunu fark ettim. Ancak IDL ile bu veriyi okumak gerçekten çok kolay. Aynı şeyi python ile yapabilir miyim?
Brian

Lütfen gönderilen cevaplardan ve yorumlardan neden memnun olmadığınızı (burada değil diğer gönderinin içinde) belirtin. Belki de daha fazla ayrıntı sağlamak için soruyu güncellemelisiniz ... Güncellendiğinde bir göz atacağım.
gecco

Paketlenmemiş bir karakteri [] dizgeye dönüştürmeniz gerekiyorsa bu yanıta bakın .
PeterM

import struct
JW

23

Genel olarak, bunun için Python'un yapı modülünü kullanmayı incelemenizi tavsiye ederim . Python ile standarttır ve sorunuzun spesifikasyonunu aşağıdakiler için uygun bir biçimlendirme dizesine çevirmek kolay olmalıdır:struct.unpack() .

Alanlar arasında / çevresinde "görünmez" dolgu varsa, bunu anlamanız ve unpack()çağrıya eklemeniz gerekeceğini, aksi takdirde yanlış bitleri okuyacağınızı unutmayın.

Paketinden çıkarılacak bir şey olması için dosyanın içeriğini okumak oldukça önemsizdir:

import struct

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

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

Bu, dosyanın en başından başladıklarını (dolgu veya gereksiz veriler olmadan) ve ayrıca yerel bayt sırasını ( @sembol) varsayarak ilk iki alanın paketini açar . IBiçimlendirme dizesinde ler "32 bit işaretsiz tamsayı" demek.


tamam, ama dosyanın baytlarını nasıl okuyacağımı bile bilmiyorum. Soruma göre dosyayı bayt 5'ten 8'e nasıl okuyabilirim ve sonucu nasıl bir tam sayıya dönüştürebilirim? Üzgünüm ama Python'da yeniyim.
Brian


11

Bir bytesnesneye ikili dosya okumak için :

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

Verilerin int0-3 baytlarından bir oluşturmak için :

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

intVerilerden birden çok URL'yi paketinden çıkarmak için:

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

0

Ben de Python ikili dosyaları okuma ve yazma konusunda eksik buldum, bu yüzden küçük bir modül yazdım (Python 3.6+ için).

Binaryfile ile böyle bir şey yaparsınız (Fortran'ı bilmediğim için tahmin ediyorum):

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)

Bunun gibi bir çıktı üreten:

{
    '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
}

Fortran'ın eklediği ek verileri atlamak için skip () kullandım, ancak bunun yerine Fortran kayıtlarını düzgün bir şekilde işlemek için bir yardımcı program eklemek isteyebilirsiniz. Bunu yaparsanız, bir çekme talebi memnuniyetle karşılanacaktır.


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

7
Muhtemelen bunun neden diğer cevaplardan daha iyi (veya en azından o kadar iyi) olduğuna dair küçük bir açıklamaya değer.
Phil

2
Bunun fortran tarafından oluşturulan ikili dosyayla çalıştığını doğruladınız mı?
agentp

1
Ve ayrıca ne işe yaradığını açıklayın ... Turşu nedir? Ne pickle.loadyüklüyor? Bir Fortran akışını, doğrudan veya sıralı dosyaları yüklüyor mu? Farklılar ve uyumlu değiller.
Vladimir F
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.