5

最近、 pythonでファイルを丸呑みする方法を尋ねられ、受け入れられた答えは次のようなものを提案しました:

with open('x.txt') as x: f = x.read()

ファイルを読み込んでデータのエンディアン表現を変換するにはどうすればよいですか?

たとえば、ビッグ エンディアンとしてパックされた単精度浮動小数点数の集まりである 1 GB のバイナリ ファイルがあり、それをリトル エンディアンに変換して numpy 配列にダンプしたいとします。以下は、これを達成するために私が書いた関数と、それを呼び出す実際のコードです。私struct.unpackはエンディアン変換を使用し、を使用してすべてを高速化しようとしましたmmap

私の質問は、丸呑みをmmapand で正しく使用していstruct.unpackますか? これを行うためのよりクリーンで高速な方法はありますか? 現在、私が持っているものはうまくいきますが、これをより良くする方法を学びたいと思っています.

前もって感謝します!

#!/usr/bin/python
from struct import unpack
import mmap
import numpy as np

def mmapChannel(arrayName,  fileName,  channelNo,  line_count,  sample_count):
    """
    We need to read in the asf internal file and convert it into a numpy array.
    It is stored as a single row, and is binary. Thenumber of lines (rows), samples (columns),
    and channels all come from the .meta text file
    Also, internal format files are packed big endian, but most systems use little endian, so we need
    to make that conversion as well.
    Memory mapping seemed to improve the ingestion speed a bit
    """
    # memory-map the file, size 0 means whole file
    # length = line_count * sample_count * arrayName.itemsize
    print "\tMemory Mapping..."
    with open(fileName, "rb") as f:
        map = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
        map.seek(channelNo*line_count*sample_count*arrayName.itemsize)

        for i in xrange(line_count*sample_count):
            arrayName[0, i] = unpack('>f', map.read(arrayName.itemsize) )[0]

        # Same method as above, just more verbose for the maintenance programmer.
        #        for i in xrange(line_count*sample_count): #row
        #            be_float = map.read(arrayName.itemsize) # arrayName.itemsize should be 4 for float32
        #            le_float = unpack('>f', be_float)[0] # > for big endian, < for little endian
        #            arrayName[0, i]= le_float

        map.close()
    return arrayName

print "Initializing the Amp HH HV, and Phase HH HV arrays..."
HHamp = np.ones((1,  line_count*sample_count),  dtype='float32')
HHphase = np.ones((1,  line_count*sample_count),  dtype='float32')
HVamp = np.ones((1,  line_count*sample_count),  dtype='float32')
HVphase = np.ones((1,  line_count*sample_count),  dtype='float32')



print "Ingesting HH_Amp..."
HHamp = mmapChannel(HHamp, 'ALPSRP042301700-P1.1__A.img',  0,  line_count,  sample_count)
print "Ingesting HH_phase..."
HHphase = mmapChannel(HHphase, 'ALPSRP042301700-P1.1__A.img',  1,  line_count,  sample_count)
print "Ingesting HV_AMP..."
HVamp = mmapChannel(HVamp, 'ALPSRP042301700-P1.1__A.img',  2,  line_count,  sample_count)
print "Ingesting HV_phase..."
HVphase = mmapChannel(HVphase, 'ALPSRP042301700-P1.1__A.img',  3,  line_count,  sample_count)

print "Reshaping...."
HHamp_orig = HHamp.reshape(line_count, -1)
HHphase_orig = HHphase.reshape(line_count, -1)
HVamp_orig = HVamp.reshape(line_count, -1)
HVphase_orig = HVphase.reshape(line_count, -1)
4

4 に答える 4

7

@Alex Martelliの答えを少し修正しました:

arr = numpy.fromfile(filename, numpy.dtype('>f4'))
# no byteswap is needed regardless of endianess of the machine
于 2009-10-27T20:42:17.937 に答える
6
with open(fileName, "rb") as f:
  arrayName = numpy.fromfile(f, numpy.float32)
arrayName.byteswap(True)

スピードと簡潔さのために打ち負かすのはかなり難しい;-)。byteswapについては、ここを参照してください(True引数は「その場で実行する」を意味します)。fromfileについては、ここを参照してください。

これは、リトルエンディアンのマシンでそのまま機能します(データはビッグエンディアンであるため、バイトスワップが必要です)。それがbyteswapを条件付きで実行する場合であるかどうかをテストできます。最後の行を、byteswapの無条件呼び出しから次のように変更します。

if struct.pack('=f', 2.3) == struct.pack('<f', 2.3):
  arrayName.byteswap(True)

つまり、リトルエンディアンのテストを条件としたbyteswapの呼び出し。

于 2009-10-27T20:19:49.657 に答える
0

CorePyを使用してASM ベースのソリューションを組み合わせることができます。ただし、アルゴリズムの他の部分から十分なパフォーマンスを得ることができるかどうかは疑問です. 1 GB のデータ チャンクの I/O と操作には、どのようにスライスしても時間がかかります。

Python でアルゴリズムのプロトタイプを作成したら、C に切り替えることが役立つと思われるもう 1 つの方法があります。全世界の DEM (高さ) データ セットを操作するために、これを 1 回行いました。解釈されたスクリプトから離れると、全体がはるかに許容できるようになりました.

于 2009-10-27T18:30:37.937 に答える