Pergunta

Foi recentemente pediu como fazer um gole arquivo em python , e a resposta aceita sugeriu algo como:

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

Como eu iria fazer isso para ler o arquivo e converter a representação endian dos dados?

Por exemplo, eu tenho um arquivo binário 1GB que é apenas um monte de precisão simples flutua embalado como um grande endian e eu quero convertê-lo em pouco endian e despejo em uma matriz numpy. Abaixo é a função que eu escrevi para alcançar este objetivo e algum código real que o chama. Eu uso struct.unpack fazer a conversão endian e tentou velocidade tudo para cima usando mmap.

A minha pergunta então é, estou usando o gole corretamente com mmap e struct.unpack? Existe um produto de limpeza, a maneira mais rápida de fazer isso? Agora o que eu tenho as obras, mas eu realmente gostaria de saber como fazer isso melhor.

Agradecemos antecipadamente!

#!/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)
Foi útil?

Solução

with open(fileName, "rb") as f:
  arrayName = numpy.fromfile(f, numpy.float32)
arrayName.byteswap(True)

Pretty difícil de bater para a velocidade e concisão ;-). Para byteswap ver aqui (os meios argumento True, "fazê-lo no lugar"); para FromFile ver aqui .

Isso funciona como é em pequenas máquinas-endian (desde que os dados são big-endian, o byteswap é necessária). Você pode testar se esse for o caso, para fazer o byteswap condicionalmente, altere a última linha de uma chamada incondicional de byteswap em, por exemplo:

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

ou seja., Uma chamada para byteswap condicional em um teste de pouca-ordenação.

Outras dicas

Um pouco modificado de @Alex Martelli resposta :

arr = numpy.fromfile(filename, numpy.dtype('>f4'))
# no byteswap is needed regardless of endianess of the machine

Você poderia Coble juntos uma solução baseada ASM usando CorePy . Pergunto-me, porém, se você pode ser capaz de obter um desempenho suficiente da outra parte de seu algoritmo. I / O e manipulações em pedaços de 1GB de dados vai demorar um pouco que sempre maneira você cortá-lo.

Uma outra coisa que você pode achar útil seria a mudança para C depois de ter um protótipo do algoritmo em python. Eu fiz isso para manipulações em um todo-mundo DEM (altura) conjunto de dados uma vez. A coisa toda foi muito mais tolerável quando cheguei longe do roteiro interpretado.

Eu esperaria algo assim para ser mais rápido

arrayName[0] = unpack('>'+'f'*line_count*sample_count, map.read(arrayName.itemsize*line_count*sample_count))

Por favor, não use map como um nome de variável

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top