バイトの読み方は知ってx.read(number_of_bytes)
いますが、Python でビットを読むにはどうすればよいですか?
バイナリ ファイルから 5 ビット (8 ビット [1 バイト] ではなく) だけを読み取る必要があります。
アイデアやアプローチはありますか?
Python は一度に 1 バイトしか読み取ることができません。完全なバイトを読み取ってから、そのバイトから必要な値を抽出する必要があります。
b = x.read(1)
firstfivebits = b >> 3
または、最上位 5 ビットではなく最下位 5 ビットが必要な場合は、次のようにします。
b = x.read(1)
lastfivebits = b & 0b11111
その他の有用なビット操作情報は、http ://wiki.python.org/moin/BitManipulation で見つけることができます。
受け入れられた答えが述べているように、標準のPython I / Oは、一度に1バイト全体しか読み書きできません。ただし、このビット単位I / Oのレシピを使用して、このようなビットのストリームをシミュレートできます。
更新
ロゼッタコードのPythonバージョンをPython2と3の両方で変更なしで動作するように変更した後、これらの変更をこの回答に組み込みました。
それに加えて、後で@mhernandezによるコメントに触発された後、Rosettaコードをさらに変更して、2つのクラスの両方のインスタンスをPythonステートメントで使用できるようにするコンテキストマネージャープロトコルと呼ばれるものをサポートします。with
最新バージョンを以下に示します。
class BitWriter(object):
def __init__(self, f):
self.accumulator = 0
self.bcount = 0
self.out = f
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.flush()
def __del__(self):
try:
self.flush()
except ValueError: # I/O operation on closed file.
pass
def _writebit(self, bit):
if self.bcount == 8:
self.flush()
if bit > 0:
self.accumulator |= 1 << 7-self.bcount
self.bcount += 1
def writebits(self, bits, n):
while n > 0:
self._writebit(bits & 1 << n-1)
n -= 1
def flush(self):
self.out.write(bytearray([self.accumulator]))
self.accumulator = 0
self.bcount = 0
class BitReader(object):
def __init__(self, f):
self.input = f
self.accumulator = 0
self.bcount = 0
self.read = 0
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
pass
def _readbit(self):
if not self.bcount:
a = self.input.read(1)
if a:
self.accumulator = ord(a)
self.bcount = 8
self.read = len(a)
rv = (self.accumulator & (1 << self.bcount-1)) >> self.bcount-1
self.bcount -= 1
return rv
def readbits(self, n):
v = 0
while n > 0:
v = (v << 1) | self._readbit()
n -= 1
return v
if __name__ == '__main__':
import os
import sys
# Determine this module's name from it's file name and import it.
module_name = os.path.splitext(os.path.basename(__file__))[0]
bitio = __import__(module_name)
with open('bitio_test.dat', 'wb') as outfile:
with bitio.BitWriter(outfile) as writer:
chars = '12345abcde'
for ch in chars:
writer.writebits(ord(ch), 7)
with open('bitio_test.dat', 'rb') as infile:
with bitio.BitReader(infile) as reader:
chars = []
while True:
x = reader.readbits(7)
if not reader.read: # End-of-file?
break
chars.append(chr(x))
print(''.join(chars))
最上位の「未使用」ビットを破棄する8ビットバイトASCIIストリームを「クランチ」し、それを読み戻す方法を示す別の使用例(ただし、どちらもコンテキストマネージャーとして使用しません)。
import sys
import bitio
o = bitio.BitWriter(sys.stdout)
c = sys.stdin.read(1)
while len(c) > 0:
o.writebits(ord(c), 7)
c = sys.stdin.read(1)
o.flush()
...そして同じストリームを「デクランチ」するには:
import sys
import bitio
r = bitio.BitReader(sys.stdin)
while True:
x = r.readbits(7)
if not r.read: # nothing read
break
sys.stdout.write(chr(x))