Hướng dẫn parsing binary data in python - phân tích cú pháp dữ liệu nhị phân trong python

Sử dụng mô -đun struct, nó cũng sẽ cho phép bạn giải thích dữ liệu nhị phân theo nhiều cách; Bạn cần xác định các loại trong định dạng chuỗi được ghi lại với thư viện đó:

struct.unpack['=HHf255s', bytes]

Ví dụ trên mong đợi thứ tự byte gốc, hai quần short không dấu, một chiếc phao và một chuỗi gồm 255 ký tự.

Ví dụ về mã của bạn trở thành:

for each_word in logData:
    var1, var2, var3 = struct.unpack['8s16s8s', each_word]

Trong trường hợp bạn gặp lỗi

for each_word in logData:
    var1, var2, var3 = struct.unpack['8s16s8s', bytes[each_word, 'utf-8']]

Nhưng có lẽ trường hợp chuỗi byte 8/16 của bạn là số nguyên dài? Trong trường hợp đó, sử dụng định dạng thích hợp cho cấu trúc.

Chỉnh sửa: Hóa ra bạn muốn đọc 8 bit [không phải byte], sau đó là 16 bit tiếp theo, sau đó là 8 bit tiếp theo, vì vậy bạn có thể đọc nó dưới dạng một [không dấu?] Chuỗi định dạng bạn nên sử dụng là

for each_word in logData:
    var1, var2, var3 = struct.unpack['8s16s8s', each_word]
3 [hoặc
for each_word in logData:
    var1, var2, var3 = struct.unpack['8s16s8s', each_word]
4 cho không dấu]. Thí dụ:bits [not bytes], then the next 16 bits, then the next 8 bits, so you can read it as one [unsigned?] byte, one short, and another byte. The format string you should use is
for each_word in logData:
    var1, var2, var3 = struct.unpack['8s16s8s', each_word]
3 [or
for each_word in logData:
    var1, var2, var3 = struct.unpack['8s16s8s', each_word]
4 for unsigned]. Example:

import struct
with open['test.bin','rb'] as f:
    var1, var2, var3 = struct.unpack['=BHB', f.read[4]]
    print[var1, var2, var3]

Mô -đun struct cung cấp các hàm cho các trường phân tích các byte thành một bộ các đối tượng python và để thực hiện chuyển đổi ngược lại, từ một tuple thành byte đóng gói. struct có thể được sử dụng với các đối tượng

for each_word in logData:
    var1, var2, var3 = struct.unpack['8s16s8s', each_word]
1,
for each_word in logData:
    var1, var2, var3 = struct.unpack['8s16s8s', each_word]
8 và
for each_word in logData:
    var1, var2, var3 = struct.unpack['8s16s8s', each_word]
9.

Mô -đun struct rất mạnh mẽ và thuận tiện, nhưng trước khi sử dụng nó, bạn nên nghiêm túc xem xét các lựa chọn thay thế, do đó, phần ngắn đầu tiên trong bài đăng này.

Contents:

  1. Chúng ta có nên sử dụng struct không?

  2. Cấu trúc 101

  3. Các cấu trúc và chế độ xem bộ nhớ

Chúng ta có nên sử dụng struct không?

Cấu trúc 101

Các cấu trúc và chế độ xem bộ nhớ

Hồ sơ nhị phân độc quyền trong thế giới thực là giòn và có thể bị hỏng dễ dàng. Ví dụ siêu đơn giản trong struct 101 sẽ phơi bày một trong nhiều cảnh báo: trường chuỗi chỉ có thể bị giới hạn bởi kích thước của nó trong byte, nó có thể được đệm bởi không gian hoặc nó có thể chứa một chuỗi kết thúc không kích thước nhất định. Ngoài ra còn có vấn đề về tính endian: thứ tự của các byte được sử dụng để đại diện cho số nguyên và phao, phụ thuộc vào kiến ​​trúc CPU.

Nếu bạn cần đọc hoặc viết từ định dạng nhị phân hiện có, tôi khuyên bạn nên cố gắng tìm một thư viện sẵn sàng sử dụng thay vì cuộn giải pháp của riêng bạn.

Cấu trúc 101

Các cấu trúc và chế độ xem bộ nhớ

Hồ sơ nhị phân độc quyền trong thế giới thực là giòn và có thể bị hỏng dễ dàng. Ví dụ siêu đơn giản trong struct 101 sẽ phơi bày một trong nhiều cảnh báo: trường chuỗi chỉ có thể bị giới hạn bởi kích thước của nó trong byte, nó có thể được đệm bởi không gian hoặc nó có thể chứa một chuỗi kết thúc không kích thước nhất định. Ngoài ra còn có vấn đề về tính endian: thứ tự của các byte được sử dụng để đại diện cho số nguyên và phao, phụ thuộc vào kiến ​​trúc CPU.

struct MetroArea {
    int year;
    char name[12];
    char country[2];
    float population;
};

Nếu bạn cần đọc hoặc viết từ định dạng nhị phân hiện có, tôi khuyên bạn nên cố gắng tìm một thư viện sẵn sàng sử dụng thay vì cuộn giải pháp của riêng bạn.

Nếu bạn cần trao đổi dữ liệu nhị phân giữa các hệ thống Python trong công ty, mô-đun Pickle là cách dễ nhất, nhưng hãy cẩn thận rằng các phiên bản khác nhau của Python sử dụng các định dạng nhị phân khác nhau theo mặc định và đọc Pickle có thể chạy mã tùy ý, vì vậy nó không an toàn cho sử dụng bên ngoài.

>>> from struct import unpack, calcsize
>>> FORMAT = 'i12s2sf'
>>> size = calcsize[FORMAT]
>>> data = open['metro_areas.bin', 'rb'].read[size]
>>> data
b"\xe2\x07\x00\x00Tokyo\x00\xc5\x05\x01\x00\x00\x00JP\x00\x00\x11X'L"
>>> unpack[FORMAT, data]
[2018, b'Tokyo\x00\xc5\x05\x01\x00\x00\x00', b'JP', 43868228.0]

Nếu trao đổi liên quan đến các chương trình bằng các ngôn ngữ khác, hãy sử dụng JSON hoặc định dạng tuần tự nhị phân đa nền tảng như bộ đệm thông báo hoặc giao thức.

Giả sử bạn cần đọc một tệp nhị phân chứa dữ liệu về các khu vực đô thị, được tạo bởi một chương trình trong C với bản ghi được xác định là ví dụ 1

Ví dụ 1. Metroarea: Một cấu trúc trong ngôn ngữ C.Dưới đây là cách đọc một bản ghi ở định dạng đó, sử dụng
for each_word in logData:
    var1, var2, var3 = struct.unpack['8s16s8s', bytes[each_word, 'utf-8']]
3:Ví dụ 2. Đọc cấu trúc C trong bảng điều khiển Python.Lưu ý cách
for each_word in logData:
    var1, var2, var3 = struct.unpack['8s16s8s', bytes[each_word, 'utf-8']]
4 trả về một tuple với bốn trường, như được chỉ định bởi chuỗi
for each_word in logData:
    var1, var2, var3 = struct.unpack['8s16s8s', bytes[each_word, 'utf-8']]
5. Các chữ cái và số trong
for each_word in logData:
    var1, var2, var3 = struct.unpack['8s16s8s', bytes[each_word, 'utf-8']]
5 là các ký tự định dạng được mô tả trong tài liệu mô -đun struct.Bảng 1 giải thích các phần tử của chuỗi định dạng từ Ví dụ 2. Bảng 1. Các phần của chuỗi định dạng
for each_word in logData:
    var1, var2, var3 = struct.unpack['8s16s8s', bytes[each_word, 'utf-8']]
8.

for each_word in logData:
    var1, var2, var3 = struct.unpack['8s16s8s', bytes[each_word, 'utf-8']]
9

phần

import struct
with open['test.bin','rb'] as f:
    var1, var2, var3 = struct.unpack['=BHB', f.read[4]]
    print[var1, var2, var3]
0

import struct
with open['test.bin','rb'] as f:
    var1, var2, var3 = struct.unpack['=BHB', f.read[4]]
    print[var1, var2, var3]
0

kích thước

import struct
with open['test.bin','rb'] as f:
    var1, var2, var3 = struct.unpack['=BHB', f.read[4]]
    print[var1, var2, var3]
2

Loại c

import struct
with open['test.bin','rb'] as f:
    var1, var2, var3 = struct.unpack['=BHB', f.read[4]]
    print[var1, var2, var3]
3

for each_word in logData:
    var1, var2, var3 = struct.unpack['8s16s8s', each_word]
1

Loại Python

import struct
with open['test.bin','rb'] as f:
    var1, var2, var3 = struct.unpack['=BHB', f.read[4]]
    print[var1, var2, var3]
5

giới hạn nội dung thực tế

import struct
with open['test.bin','rb'] as f:
    var1, var2, var3 = struct.unpack['=BHB', f.read[4]]
    print[var1, var2, var3]
6

for each_word in logData:
    var1, var2, var3 = struct.unpack['8s16s8s', each_word]
1

4 byte

import struct
with open['test.bin','rb'] as f:
    var1, var2, var3 = struct.unpack['=BHB', f.read[4]]
    print[var1, var2, var3]
8

phần

import struct
with open['test.bin','rb'] as f:
    var1, var2, var3 = struct.unpack['=BHB', f.read[4]]
    print[var1, var2, var3]
9

import struct
with open['test.bin','rb'] as f:
    var1, var2, var3 = struct.unpack['=BHB', f.read[4]]
    print[var1, var2, var3]
9

kích thước

Loại c

Loại Python

$ python3 metro_read.py
2018    Tokyo, JP       43,868,228
2015    Shanghai, CN    38,700,000
2015    Jakarta, ID     31,689,592

giới hạn nội dung thực tế

Ví dụ 3. Metro_read.py: Liệt kê tất cả các bản ghi từ

struct MetroArea {
    int year;
    char name[12];
    char country[2];
    float population;
};
1

from struct import iter_unpack

FORMAT = 'i12s2sf'                             # [1]

def text[field: bytes] -> str:                 # [2]
    octets = field.split[b'\0', 1][0]          # [3]
    return octets.decode['cp437']              # [4]

with open['metro_areas.bin', 'rb'] as fp:      # [5]
    data = fp.read[]

for fields in iter_unpack[FORMAT, data]:       # [6]
    year, name, country, pop = fields
    place = text[name] + ', ' + text[country]  # [7]
    print[f'{year}\t{place}\t{pop:,.0f}']

  1. Định dạng struct.

  2. Chức năng tiện ích để giải mã và làm sạch các trường

    for each_word in logData:
        var1, var2, var3 = struct.unpack['8s16s8s', each_word]
    
    1; Trả về A ________ 12. [2]

  3. Xử lý chuỗi C chấm dứt NULL: Chia một lần trên

    struct MetroArea {
        int year;
        char name[12];
        char country[2];
        float population;
    };
    6, sau đó lấy phần đầu tiên.

  4. Giải mã

    for each_word in logData:
        var1, var2, var3 = struct.unpack['8s16s8s', each_word]
    
    1 thành
    for each_word in logData:
        var1, var2, var3 = struct.unpack['8s16s8s', each_word]
    
    2.

  5. Mở và đọc toàn bộ tệp ở chế độ nhị phân;

    >>> from struct import unpack, calcsize
    >>> FORMAT = 'i12s2sf'
    >>> size = calcsize[FORMAT]
    >>> data = open['metro_areas.bin', 'rb'].read[size]
    >>> data
    b"\xe2\x07\x00\x00Tokyo\x00\xc5\x05\x01\x00\x00\x00JP\x00\x00\x11X'L"
    >>> unpack[FORMAT, data]
    [2018, b'Tokyo\x00\xc5\x05\x01\x00\x00\x00', b'JP', 43868228.0]
    7 là một đối tượng
    for each_word in logData:
        var1, var2, var3 = struct.unpack['8s16s8s', each_word]
    
    1.

  6. >>> from struct import unpack, calcsize
    >>> FORMAT = 'i12s2sf'
    >>> size = calcsize[FORMAT]
    >>> data = open['metro_areas.bin', 'rb'].read[size]
    >>> data
    b"\xe2\x07\x00\x00Tokyo\x00\xc5\x05\x01\x00\x00\x00JP\x00\x00\x11X'L"
    >>> unpack[FORMAT, data]
    [2018, b'Tokyo\x00\xc5\x05\x01\x00\x00\x00', b'JP', 43868228.0]
    9 Trả về một trình tạo tạo một bộ trường cho mỗi chuỗi byte khớp với chuỗi định dạng.

  7. Các trường

    struct MetroArea {
        int year;
        char name[12];
        char country[2];
        float population;
    };
    2 và
    struct MetroArea {
        int year;
        char name[12];
        char country[2];
        float population;
    };
    3 cần xử lý thêm theo hàm
    $ python3 metro_read.py
    2018    Tokyo, JP       43,868,228
    2015    Shanghai, CN    38,700,000
    2015    Jakarta, ID     31,689,592
    2.

Mô-đun struct không cung cấp cách nào để chỉ định các trường chuỗi chấm dứt null. Khi xử lý một trường như

struct MetroArea {
    int year;
    char name[12];
    char country[2];
    float population;
};
2 trong ví dụ trên, sau khi giải nén, chúng tôi cần kiểm tra các byte được trả về để loại bỏ
struct MetroArea {
    int year;
    char name[12];
    char country[2];
    float population;
};
6 đầu tiên và tất cả các byte sau khi nó trong trường đó. Hoàn toàn có thể là byte sau
struct MetroArea {
    int year;
    char name[12];
    char country[2];
    float population;
};
6 đầu tiên và cho đến cuối trường là rác. Bạn thực sự có thể thấy điều đó trong ví dụ 2.

Chế độ xem bộ nhớ có thể giúp thử nghiệm và gỡ lỗi các chương trình dễ dàng hơn bằng cách sử dụng struct, như phần tiếp theo giải thích.

Các cấu trúc và chế độ xem bộ nhớ

Loại Python từ

for each_word in logData:
    var1, var2, var3 = struct.unpack['8s16s8s', each_word]
9 không cho phép bạn tạo hoặc lưu trữ các chuỗi byte. Thay vào đó, nó cung cấp quyền truy cập bộ nhớ được chia sẻ cho các lát dữ liệu từ các chuỗi nhị phân khác, các mảng được đóng gói và các bộ đệm như hình ảnh Thư viện hình ảnh Python [PIL], [3] mà không sao chép byte.

Ví dụ 4 cho thấy việc sử dụng

for each_word in logData:
    var1, var2, var3 = struct.unpack['8s16s8s', each_word]
9 và struct cùng nhau để trích xuất chiều rộng và chiều cao của hình ảnh GIF.

Ví dụ 4. Sử dụng MemoryView và Struct để kiểm tra tiêu đề hình ảnh GIF

>>> import struct
>>> fmt = '

Bài Viết Liên Quan

Chủ Đề