Đọc tệp nhị phân bằng python


104

Tôi thấy đặc biệt khó khăn khi đọc tệp nhị phân bằng Python. Bạn có thể giúp tôi một tay? Tôi cần đọc tệp này, tệp này trong Fortran 90 có thể dễ dàng đọc bằng

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)

Cụ thể, định dạng tệp là:

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. 

Làm cách nào tôi có thể đọc nội dung này bằng Python? Tôi đã thử mọi thứ nhưng nó không bao giờ hiệu quả. Có bất kỳ cơ hội nào tôi có thể sử dụng chương trình f90 trong python, đọc tệp nhị phân này và sau đó lưu dữ liệu mà tôi cần sử dụng không?


1
Tệp này được viết bởi chương trình Fortran? Nếu vậy, nó đã được ghi như thế nào, vì Fortran, theo mặc định, thêm dữ liệu bổ sung trước mỗi bản ghi mà nó ghi vào tệp. Bạn có thể cần phải cẩn thận với điều này khi đọc dữ liệu.
Chris

1
Vui lòng bỏ qua nhận xét trước đây của tôi, các số 8 và 4 * N rõ ràng là dữ liệu bổ sung này.
Chris

2
Ngoài ra, hãy xem câu trả lời cho câu hỏi đọc tệp nhị phân trong python .
Chris

fromfileChức năng của Numpy giúp bạn dễ dàng đọc các tệp nhị phân. Tôi khuyến khích điều đó.
littleO

... và luôn đề phòng những mối nguy hiểm của bạn, đặc biệt. khi chuyển giữa các máy tính của nhà sản xuất khác nhau.
DragonLord

Câu trả lời:


155

Đọc nội dung tệp nhị phân như sau:

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

sau đó "giải nén" dữ liệu nhị phân bằng struct.unpack :

Các byte bắt đầu: struct.unpack("iiiii", fileContent[:20])

Phần nội dung: bỏ qua byte đầu đề và byte cuối (= 24); Phần còn lại tạo thành phần thân, để biết số byte trong phần thân thực hiện phép chia số nguyên cho 4; Thương số thu được được nhân với chuỗi 'i'để tạo định dạng chính xác cho phương thức giải nén:

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

Byte kết thúc: struct.unpack("i", fileContent[-4:])


Bạn có thể vui lòng nhìn vào bài viết khác này được không? stackoverflow.com/questions/8092469/… ... Tôi lại muốn đọc một tệp nhị phân khác, nhưng trong trường hợp này, tôi không biết chi tiết cấu trúc byte. Ví dụ, tôi đã tìm ra rằng đôi khi có số nguyên 8. Tuy nhiên, với IDL, việc đọc dữ liệu này thực sự đơn giản. Tôi có thể làm điều tương tự với python không?
Brian

Vui lòng cho biết (bên trong bài viết khác, không phải ở đây) tại sao bạn không hài lòng với các câu trả lời và nhận xét đã đăng. Có lẽ bạn cũng nên cập nhật câu hỏi để cung cấp thêm chi tiết ... Tôi sẽ xem xét nó khi nó được cập nhật.
gecco

Hãy xem câu trả lời này nếu bạn cần chuyển đổi một char [] đã giải nén thành một chuỗi.
PeterM

import struct
JW

23

Nói chung, tôi khuyên bạn nên xem xét sử dụng mô-đun struct của Python cho việc này. Nó tiêu chuẩn với Python và sẽ dễ dàng dịch đặc tả câu hỏi của bạn thành một chuỗi định dạng phù hợp struct.unpack().

Lưu ý rằng nếu có khoảng đệm "vô hình" giữa / xung quanh các trường, bạn sẽ cần phải tìm ra điều đó và đưa nó vào lệnh unpack()gọi, nếu không bạn sẽ đọc sai các bit.

Đọc nội dung của tệp để có thứ gì đó để giải nén là khá đơn giản:

import struct

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

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

Thao tác này giải nén hai trường đầu tiên, giả sử chúng bắt đầu ở phần đầu của tệp (không có phần đệm hoặc dữ liệu không liên quan) và cũng giả định thứ tự byte gốc ( @biểu tượng). Các Is trong chuỗi định dạng có nghĩa là "số nguyên không dấu, 32 bit".


ok, nhưng tôi thậm chí không biết cách đọc các byte của tệp. Từ câu hỏi của tôi, làm thế nào tôi có thể đọc tệp từ byte 5 đến 8 và sau đó chuyển đổi kết quả thành số nguyên? Xin lỗi, nhưng tôi chưa quen với Python.
Brian

14

Bạn có thể sử dụng numpy.fromfile, có thể đọc dữ liệu từ cả tệp văn bản và tệp nhị phân. Trước tiên, bạn sẽ xây dựng một kiểu dữ liệu, đại diện cho định dạng tệp của bạn, bằng cách sử dụng numpy.dtype, sau đó đọc kiểu này từ tệp bằng cách sử dụng numpy.fromfile.


2
Dễ dàng bỏ lỡ điều này! Docs hơi mỏng; xem reddit.com/r/Python/comments/19q8nt/… để biết một số cuộc thảo luận
mất

11

Để đọc một tệp nhị phân cho một bytesđối tượng:

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

Để tạo một inttừ byte 0-3 của dữ liệu:

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

Để giải nén nhiều ints từ dữ liệu:

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

0

Tôi cũng thấy thiếu Python khi đọc và ghi các tệp nhị phân, vì vậy tôi đã viết một mô-đun nhỏ (cho Python 3.6+).

Với tệp nhị phân, bạn sẽ làm như thế này (tôi đoán vậy, vì tôi không biết Fortran):

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)

Cái nào tạo ra đầu ra như thế này:

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

Tôi đã sử dụng Bỏ qua () để bỏ qua dữ liệu bổ sung mà Fortran thêm vào, nhưng bạn có thể muốn thêm một tiện ích để xử lý các bản ghi Fortran đúng cách. Nếu bạn làm vậy, một yêu cầu kéo sẽ được hoan nghênh.


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

6
Có lẽ chỉ cần giải thích một chút về lý do tại sao câu trả lời này tốt hơn (hoặc ít nhất là tốt như) các câu trả lời khác.
Phil

2
bạn đã kiểm tra xác minh điều này hoạt động với mã nhị phân được tạo fortran chưa?
agentp

1
Và cũng giải thích nó làm gì ... Dưa chua là gì? Làm những gì pickle.loadtải? Nó có tải một luồng Fortran, các tệp trực tiếp hay tuần tự không? Chúng khác nhau và không tương thích.
Vladimir F
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.