Pythonバイナリデータ処理

14746 ワード

目次
  • 前言
  • strとbytes
  • base 64モジュール
  • structモジュール
  • 参照リンク
  • 前言
    本明細書に係るコードはpython 3に基づいている.x.
    strとbytes
    コードを書くとき、文字列の処理に関わることがよくありますが、文字列の符号化の問題はよく頭が痛いです.もちろん、この文章は符号化について話すのではなく、主にバイナリ処理について話しています.python 3はbytesを提供してくれました.bytesを利用して符号化エラーの問題をある程度緩和することができます.bytesはバイトシーケンスであり、符号化とは関係ありません.まず例を見てみましょう.
    _str = 'str'
    print(type(_str))
    #     
    
    _bytes = b'bytes'
    print(type(_bytes))
    #    
    

    違いが見えますね.文字列を定義するときに、文字列引用符の前にbを付けると、bytesが定義されます.上の_bytes変数はバイトシーケンスですが、print()が出てくるのは文字列の前にbが付いているだけで、strとあまり変わらないようです.では、次のコードを見てみましょう.
    _str = '  '
    print(_str)
    #   
    
    _bytes = '  '.encode()
    print(_bytes)
    # b'\xe4\xb8\xad\xe5\x9b\xbd'
    

    中国語ではstrが印刷されるのはそれ自体で、bytesが印刷されるのは16進符号化です.ネット上で中国語strを他の人に送信するとき、あなたが使用している符号化フォーマットが相手と一致しない場合、相手がstrを直接読み取るのは文字化けしている可能性がありますが、bytesにはこの問題はありません.上のコードはstrとbytesの変換にも関連していますが、ここでもお話しします.まずコードを見てください.
    _str = '  '
    print(type(_str))  # 
    print(_str)  #   
    
    _bytes = _str.encode()
    print(type(_bytes))  # 
    print(_bytes)  # b'\xe4\xb8\xad\xe5\x9b\xbd'
    
    new_str = _bytes.decode()
    print(type(new_str))  # 
    print(new_str)  #   
    

    str回転bytesはencode()メソッド、bytes回転strはdecode()メソッド、encode()メソッドはencoding='utf-8'のデフォルトであることがわかります.またstrには、bytesのほとんどの方法がありますが、この文章は文字列処理の問題を主に話しているわけではないので、ここでは展開しません.
    base 64モジュール
    次にbase 64モジュールについて説明します.まずbase 64は、64文字でバイナリデータを表す方法である.具体的には、まず、バイナリデータを表す64文字を定義します.
    ['a', 'b', ..., '+', '/']  #     60   
    

    そして、処理が必要なバイナリデータは、3バイト毎のグループ、すなわち3 x 8 = 24 bitにグループ化される.そしてこの24ビットを4グループに分け,各グループ6ビットとする.各グループの6 bitは0から63の間の数字を表すことができ、最初に定義された64文字テーブルを調べてバイナリデータの文字表現を得ることができます.この場合,元のバイナリデータの長さが増加すると,データ伝送の圧力が増大するのではないか.ここで、base 64が処理する主な処理は、文字化けしの問題を表示することであることを明らかにする必要がある.バイナリファイルを直接開くと、文字化けして出てくることが多いが、base 64で表すと、これらのデータを開くと、メールや画像など、中身がはっきり見える.もちろんURL、Cookie、Webページで少量のデータを転送するためにも使われている.もう一つ質問ですが、元のバイナリデータのバイト数が3の整数倍でなければどうしますか?この場合、base 64は、元のバイナリデータの末尾に\x00を追加してデータを補完し、その後、符号化された文字列において、これらが補完された箇所を=と表し、復号化時にこれらの=が除去され、正確な元のバイナリデータも得られる.これらの操作はpythonのbase 64モジュールで自動的に完了し、実際には関心を持っていません.こんなにたくさん話したので、pythonでbase 64の使い方を見てみましょう.
    import base64
    
    _bytes = b'test bytes'
    
    b64 = base64.b64encode(_bytes)
    print(b64)  # b'dGVzdCBieXRlcw=='
    
    new_bytes = base64.b64decode(b64)
    print(new_bytes)  # b'test bytes'
    

    なお、上記のb'test bytes'は10バイトであり、base 64処理後に2つの=が追加され、12バイト、すなわち3の整数倍となる.最後に、前述したように、base 64はURLを処理するために使用できますが、base 64の64文字には+ /があり、これらの記号はURLでは直接パラメータとして使用できません.従って、base 64は、base 64が符号化された文字列の+ /- _に置き換えるurl safeの処理方式も提供する.次に例を示します.
    import base64
    
    _bytes = b'\xfd\xcf\xbe'
    b64 = base64.b64encode(_bytes)
    print(b64)  # b'/c++'
    
    us_b64 = base64.urlsafe_b64encode(_bytes)
    print(us_b64)  # b'_c--'
    
    new_bytes = base64.urlsafe_b64decode(us_b64)
    print(new_bytes)  # b'\xfd\xcf\xbe'
    

    urlsafeを通ってb 64 encode()符号化文字列は、b 64 encode()符号化文字列とは確かに異なる.また、base 64の64文字の順序はカスタマイズ可能であり、これにより符号化をカスタマイズすることができるが、一般的にはこの必要はない.
    structモジュール
    最後にstructモジュールについてお話しします.これもpythonでよく使われるバイナリデータを処理するモジュールです.structモジュールはpythonデータとpython bytesオブジェクトとして表されるC構造体(struct)との間の変換を処理するために使用され、アプリケーションシーンは一般的にファイルとネットワーク伝送中のバイナリデータを処理する.structモジュールの応用例を見てみましょう.
    struct s_data {
    	unsigned short id;
    	unsigned int length;
    	char[5] data;
    }
    

    上記のようなC構造体があるとしたら、python値とどのように変換しますか?コードを参照:
    from struct import Struct
    
    p_id = 0
    p_length = 5
    p_data = b'hello'
    
    c_struct = Struct('>HI5s')
    packed = c_struct.pack(p_id, p_length, p_data)
    print(packed)  # b'\x00\x00\x00\x00\x00\x05hello'
    
    unpacked = c_struct.unpack(b'\x00\x00\x00\x00\x00\x05hello')
    print(unpacked)  # (0, 5, b'hello')
    

    上記のコードでは、まずpythonで構造体の各メンバーを定義し、pack()メソッドを呼び出してbytesにパッケージ化し、Cとデータ交換を行うことができます.また、次の2行のコードでは、Cからバイナリデータの列を受け取り、unpackメソッドを呼び出して解析することができます(解析されたデータはメタグループに置かれています).次の行のコードでは、C構造体のデータフォーマットを実際に定義します.
    c_struct = Struct('>HI5s')
    

    1番目のシンボル>は、データが大端方式(big-endian)で格納されていることを示し、これは主に、あるC/C++を考慮したコンパイラがバイトアラインメントを使用していることを示す.この文字は、バイト順、サイズ、パッケージング後のデータの位置合わせを定義しています.次の表を参照してください.
    Character
    Byte Order
    Size
    Alignment
    @
    native
    native
    native
    =
    native
    standard
    none
    <
    little-endian
    standard
    none
    >
    big-endian
    standard
    none
    !
    network(=big-endian)
    standard
    none
    プログラムを書くときに最初の文字を上記の表の文字として定義しなかった場合、デフォルトは@です.プラットフォームに関係のないデータフォーマットを処理したい場合は、sizeをstandardとし、nativeを使用しないでください.>記号の後ろのいくつかの記号のうち、HはCのunsigned shortを表し、IはCのunsigned intを表し、sはCのchar[]を表し、5sは5要素のchar配列を表す.Cとpythonの対応するタイプを以下に列挙します.
    Format
    C Type
    Python Type
    Standard size
    x
    pad byte
    no value
    c
    char
    bytes of length 1
    1
    b
    signed char
    integer
    1
    B
    unsigned char
    integer
    1
    ?
    _Bool
    bool
    1
    h
    short
    integer
    2
    H
    unsigned short
    integer
    2
    i
    int
    integer
    4
    I
    unsigned int
    integer
    4
    l
    long
    integer
    4
    L
    unsigned long
    integer
    4
    q
    long long
    integer
    8
    Q
    unsigned long long
    integer
    8
    n
    ssize_t
    integer
    N
    size_t
    integer
    e
    float
    2
    f
    float
    float
    4
    d
    double
    float
    8
    s
    char[]
    bytes
    p
    char[]
    bytes
    P
    void*
    integer
    Standard size列に固定値があるのは、プラットフォームに関係なくサイズであり、具体的な値がないのは、プラットフォームに関連していることに注意してください.最後に、上記のコードについては、実際にはこのように書くこともできます.
    import struct
    
    p_id = 0
    p_length = 5
    p_data = b'hello'
    
    
    packed = struct.pack('>HI5s', p_id, p_length, p_data)
    print(packed)  # b'\x00\x00\x00\x00\x00\x05hello'
    
    unpacked = struct.unpack('>HI5s', b'\x00\x00\x00\x00\x00\x05hello')
    print(unpacked)  # (0, 5, b'hello')
    

    しかし、この書き方は実例的な方法が優雅ではないと思います.特にコードの中で同じ構造が複数の場所に現れたときです.Structインスタンスを作成すると、フォーマット文字列は1回のみ指定され、すべての操作が集中的に処理されます.これにより、コードのメンテナンスが簡単になります(コードを変更するだけでよいため).
    リファレンスリンク
    廖雪峰base 64教程廖雪峰struct教程python 3 module struct doc