2009-10-27 18 views
5

Nó được gần đây đã hỏi how to do a file slurp in python, và câu trả lời chấp nhận đề nghị một cái gì đó như:Python file Slurp w/chuyển đổi endian

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

Làm thế nào tôi sẽ đi về việc này để đọc các tập tin trong và chuyển đổi các đại diện về cuối của dữ liệu? Ví dụ, tôi có một tập tin nhị phân 1GB chỉ là một bó nổi chính xác đơn đóng gói như một endian lớn và tôi muốn chuyển đổi nó thành một endian nhỏ và đổ vào một mảng numpy. Dưới đây là hàm tôi đã viết để thực hiện điều này và một số mã thực sự gọi nó. Tôi sử dụng struct.unpack thực hiện chuyển đổi cuối cùng và cố gắng tăng tốc mọi thứ bằng cách sử dụng mmap.

Câu hỏi của tôi là, tôi có đang sử dụng chính xác slurp với mmapstruct.unpack không? Có cách nào sạch hơn, nhanh hơn để thực hiện việc này không? Ngay bây giờ những gì tôi đã làm việc, nhưng tôi thực sự muốn tìm hiểu làm thế nào để làm điều này tốt hơn.

Cảm ơn trước!

#!/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) 
+0

tôi muốn thêm vào này, đối với bất kỳ ai khác tìm thấy bài này hữu ích. Chạy mã gốc tôi đã mất khoảng 80 giây hoặc lâu hơn. Chạy các giải pháp được cung cấp bởi Alex Martelli và J F Sebastian là ít hơn một giây. Chương trình gọi hàm này thực hiện quá nhiều lần. Như vậy, thời gian chạy đã giảm đáng kể. Cảm ơn cả hai vì sự giúp đỡ và để dạy tôi điều gì đó =) – Foofy

Trả lời

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

Khá khó khăn để đánh bại đối với tốc độ VÀ conciseness ;-). Đối với byteswap, hãy xem here (đối số True có nghĩa là "làm điều đó tại chỗ"); cho fromfile xem here.

Tính năng này hoạt động như trên các máy nhỏ gọn (vì dữ liệu là lớn, nên cần có bytewap). Bạn có thể kiểm tra nếu đúng như vậy để làm byteswap có điều kiện, thay đổi dòng cuối cùng từ một cuộc gọi vô điều kiện để byteswap vào, ví dụ:

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

tức, một cuộc gọi đến byteswap có điều kiện vào một cuộc thử nghiệm ít endianness .

+0

đó là đơn giản đáng kể.cảm ơn bạn điều kỳ lạ là tôi đã thấy những người đó khi cố gắng tìm ra cách để làm điều này, nhưng nó không đăng ký vì một lý do nào đó. đi kèm với kinh nghiệm tôi giả sử =) – Foofy

+2

numpy.float32 có thứ tự byte gốc có thể không phải lúc nào cũng là người lớn. http://stackoverflow.com/questions/1632673/python-file-slurp-w-endian-conversion/1633525#1633525 – jfs

+0

Thực tế, nó hầu như sẽ là một công cụ nhỏ, nhưng nếu bạn đang chạy, ví dụ: trên một máy Power PC nó sẽ là endian lớn (nếu đó là một vấn đề chỉ có điều kiện bỏ qua các cuộc gọi bytewap - hãy để tôi chỉnh sửa câu trả lời để thêm rằng bit). –

0

Bạn có thể cùng nhau sử dụng ASM based solution sử dụng CorePy. Tôi tự hỏi, mặc dù, nếu bạn có thể đạt được hiệu suất đủ từ một số phần khác của thuật toán của bạn. I/O và các thao tác trên khối dữ liệu 1GB sẽ mất một khoảng thời gian mà bạn từng cắt nó.

Một điều khác bạn có thể thấy hữu ích là chuyển sang C khi bạn đã tạo mẫu thuật toán trong python. Tôi đã làm điều này cho các thao tác trên toàn bộ dữ liệu DEM (chiều cao) toàn bộ được thiết lập một lần. Toàn bộ mọi thứ đã được chấp nhận nhiều hơn một khi tôi đã đi từ kịch bản giải thích.

0

tôi mong đợi một cái gì đó như thế này để được nhanh hơn

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

Xin đừng dùng map như một tên biến

7

Hơi sửa đổi @Alex Martelli's answer:

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

Bạn có thể muốn kết hợp điều đó với .astype để biến nó thành định dạng gốc, ví dụ: 'arr = numpy.fromfile (tên tệp, numpy.dtype ('> f4')). astype (np.float32)' – RolKau

+0

@RolKau no. Hãy thử chạy một số mã có và không có cuộc gọi và xem điều gì xảy ra. – jfs

+0

@JFSebastian Có lẽ tôi đã ngoại suy từ điều này quá xa so với trường hợp thực tế trong câu hỏi, nhưng hãy xem xét mã Python: 'b = bytearray ([0, 0, 0, 1]); a = numpy.frombuffer (b, dtype = numpy.dtype ('> i4')); c = a.astype (numpy.int32); (a.tostring(), c.tostring()) '. Trên nền tảng của tôi (Linux, Python 2.7, x86_64) Tôi nhận được kết quả a = '\ x00 \ x00 \ x00 \ x01', c =' \ x01 \ x00 \ x00 \ x00', mà tôi giải thích rằng chỉ c được lưu trữ trong nội bộ như một người ít tuổi. – RolKau