web-dev-qa-db-ja.com

Pythonでのバイナリデータの検索/読み取り

バイナリファイル(この場合はjpg)を読み込んでいますが、そのファイルでいくつかの値を見つける必要があります。興味のある方のために、バイナリファイルはjpgであり、バイナリ構造を 詳細はこちら として探すことで、そのサイズを選択しようとしています。

バイナリデータでFFC0を見つけ、いくつかのバイトをスキップしてから、4バイトを読み取る必要があります(これでイメージのサイズがわかります)。

バイナリデータの値を検索する良い方法は何ですか? 「検索」に相当するもの、またはreのようなものはありますか?

25
Parand

実際にファイルを文字列にロードし、str.find()メソッドを使用してその文字列からバイトシーケンス0xffc0を検索できます。任意のバイトシーケンスで機能します。

これを行うコードはいくつかの事柄に依存します。バイナリモードでファイルを開き、Python 3を使用している場合(両方ともこのシナリオではおそらくベストプラクティスです)、(文字ではなく)バイト文字列を検索する必要があります。文字列)、つまり、文字列の前にbを付ける必要があります。

with open(filename, 'rb') as f:
    s = f.read()
s.find(b'\xff\xc0')

Python 3でファイルをテキストモードで開く場合、文字列を検索する必要があります。

with open(filename, 'r') as f:
    s = f.read()
s.find('\xff\xc0')

これを行う特別な理由はありませんが。以前の方法に比べて利点はありません。バイナリファイルとテキストファイルを異なる方法で処理するプラットフォーム(Windowsなど)を使用している場合、問題が発生する可能性があります。

Python 2はバイト文字列と文字列を区別しないため、そのバージョンを使用している場合、bb'\xff\xc0'に含めるか除外するかは関係ありません。また、プラットフォームがバイナリファイルとテキストファイルを同じように処理する場合(MacやLinuxなど)、'r'または'rb'をファイルモードとして使用するかどうかは関係ありません。ただし、上位互換性のためだけに上記の最初のコードサンプルのようなものを使用することをお勧めします。Python 3に切り替えた場合に備えて、修正する必要が1つ少なくなります。

16
David Z

bitstring モジュールは、ほとんどこの目的のために設計されました。あなたの場合、次のコード(私はテストしていません)が説明に役立つはずです。

from bitstring import ConstBitStream
# Can initialise from files, bytes, etc.
s = ConstBitStream(filename='your_file')
# Search to Start of Frame 0 code on byte boundary
found = s.find('0xffc0', bytealigned=True)
if found:
    print("Found start code at byte offset %d." % found[0])
    s0f0, length, bitdepth, height, width = s.readlist('hex:16, uint:16, 
                                                        uint:8, 2*uint:16')
    print("Width %d, Height %d" % (width, height))
7
Scott Griffiths

ファイル全体をメモリに読み込んで検索し、新しいファイルをディスクに書き込む代わりに、mmapモジュールを使用できます。 mmapはnotファイル全体をメモリに格納し、インプレース変更を許可します。

#!/usr/bin/python

import mmap

with open("hugefile", "rw+b") as f:
    mm = mmap.mmap(f.fileno(), 0)
    print mm.find('\x00\x09\x03\x03')
5

reモジュールdoesは、文字列およびバイナリデータ(str in Python 2およびbytes in Python 3)なので、str.findだけでなくタスクにも使用できます。

4

find() メソッドは、サブルーチンの位置を知る必要がある場合にのみ使用してください。そうでない場合は、in演算子を使用できます。次に例を示します。

with open("foo.bin", 'rb') as f:
    if b'\x00' in f.read():
        print('The file is binary!')
    else:
        print('The file is not binary!')
2
kenorb

まあ、明らかにあります [〜#〜] pil [〜#〜] 画像モジュールには属性としてサイズがあります。あなたが提案したとおりのサイズを正確に取得したい場合は、ファイルをロードせずに、1行ずつ実行する必要があります。それを行うための最も良い方法ではありませんが、うまくいくでしょう。

2
fridder

Python 3.xでは、次のようにバイト文字列を別のバイト文字列で検索できます。

>>> byte_array = b'this is a byte array\r\n\r\nXYZ\x80\x04\x95 \x00\x00\x00\x00\x00'
>>> byte_array.find('\r\n\r\n'.encode())
20
>>>
2
caleb

Python> = 3.2の場合:

import re

f = open("filename.jpg", "rb")
byte = f.read()
f.close()

matchObj = re.match( b'\xff\xd8.*\xff\xc0...(..)(..).*\xff\xd9', byte, re.MULTILINE|re.DOTALL)
if matchObj:
    # http://stackoverflow.com/questions/444591/convert-a-string-of-bytes-into-an-int-python
    print (int.from_bytes(matchObj.group(1), 'big')) # height
    print (int.from_bytes(matchObj.group(2), 'big')) # width
0
kissson