在读取二进制文件时搜索()

时间:2012-05-23 19:11:39

标签: python binary-data seek

我是Python的超级初学者;我宁愿被抛入深渊。一点背景:我们正在阅读的文件来自声纳成像相机;目前我正在尝试读入写入文件的属性,如日期,文件名,帧数,光束数等。首先,我想阅读FILE标题。然后,对于每个帧,我想读取FRAME标题。我需要读取文件头已经停止的帧头...我相信我需要seek()才能做到这一点。这是我目前的代码,用于读取文件头(已成功完成)并从帧头的信息结束处开始:

编辑代码:

import math, struct
def __init__(didson):
    print "this better work"

def get_file_header(data,offset=0):
    fileheader={}
    winlengths=[1.125,2.25,4.5,9,18,36]
    fileheader['filetype']=struct.unpack("3s",didson_data[0:3])
    fileheader['fileversion']=struct.unpack('B',didson_data[3:4])[0]
    fileheader['numframes']=struct.unpack('l',didson_data[4:8])
    fileheader['framerate']=struct.unpack('l',didson_data[8:12])
    fileheader['resolution']=struct.unpack('i',didson_data[12:16])
    fileheader['numbeams']=struct.unpack('i',didson_data[16:20])
    fileheader['samplerate']=struct.unpack('f',didson_data[20:24])
    fileheader['samplesperchannel']=struct.unpack('l',didson_data[24:28])
    fileheader['receivergain']=struct.unpack('l',didson_data[28:32])
    fileheader['windowstart']=struct.unpack('i',didson_data[32:36])
    fileheader['winlengthsindex']=struct.unpack('i',didson_data[36:40])
    fileheader['reverse']=struct.unpack('l',didson_data[40:44])
    fileheader['serialnumber']=struct.unpack('l',didson_data[44:48])
    fileheader['date']=struct.unpack("10s",didson_data[48:58])
    #fileheader['???']=struct.unpack('26s',didson_data[58:84])
    fileheader['idstring']=struct.unpack("33s",didson_data[84:117])
    #fileheader['????2']=struct.unpack('235s',didson_data[117:352])
    fileheader['framestart']=struct.unpack('i',didson_data[352:356])
    fileheader['frameend']=struct.unpack('i',didson_data[356:360])
    fileheader['timelapse']=struct.unpack('i',didson_data[360:364])
    fileheader['recordInterval']=struct.unpack('i',didson_data[364:368])
    fileheader['radioseconds']=struct.unpack('i',didson_data[368:372])
    fileheader['frameinterval']=struct.unpack('i',didson_data[372:376])

    return fileheader




def num_datagrams(didson_data):
    assert(len(didson_data) % datagram_size==0)
    return len(didson_data)/datagram_size

def get_offset(datagram_number):
    return datagram_number * datagram_size

def didson_print(fileheader):
    print fileheader
    for key in fileheader:
        print ' ',key, fileheader[key]


def main():
    didson_file=open('C:/vprice/DIDSON/DIDSON Data/test.ddf', 'rb')
    didson_data=didson_file.read()
    print 'Number of datagrams:', num_datagrams(didson_data)
    didson_print(datagram)


if __name__=='main':
    main()

现在,如果我运行“main”,我能逐行阅读吗?我不确定它是否是每行一个值...我基本上经过并逐字逐句地计算出哪些标头值位于哪里。

任何帮助都将不胜感激!!

3 个答案:

答案 0 :(得分:2)

您将文件的全部内容读入didson_data,然后将文件处理程序didson_file恢复为零,并且从未将所有字段从{{1并且没有单步执行文件中的行/块,所以当然你的第二个didson_data仍然位于零位置,因为你没有移动到任何地方,因为你寻求定位零。

答案 1 :(得分:0)

为什么不继续一次性读取所有标题,而不是整个文件。然后,您的文件将准备好开始读取标题之后的数据。看起来更改了read

didson_data=didson_file.read()

pos=didson_file.seek(0,0)

只是:

didson_data=didson_file.read(377)

只会这样做,将位置保留在十进制偏移量377处,紧接在frameinterval标题之后。

没有理由让保存这么少的内存变得更加复杂。

一种更通用的解决方案,用于读取变量块中的其余文件,并跟踪您的位置,将使用您自己的函数。它可以读取文件的大小足以容纳最大可能的数据元素,找出数据元素的实际大小,将数据元素保存为字符串,寻找(函数开始时文件中的传入偏移量)+(刚检索的数据元素的长度,然后返回数据元素字符串。

基本上:

您将被要求越过标题然后重复调用

def get_chunk(fileobject):
    result = fileobject.read(1024)
    if len(result) == 0: # End of file
        return Null
    ## Determine what this is = thing 
    fileobject.seek(fileobject.tell()-1024+len(thing)
    return thing

直到它返回Null

 while True:
        the_thing = get_chunk(didson_file)
        if not the_thing: # It's a Null--it's the end of the file
            return
        # process the_thing
# End the program

一旦你越过标题,你将不得不以某种方式解析一个对象,并确定它有多长。 get_chunk函数可以在Python中返回不同类型的对象。只需查看the_think的类型,* #process the_thing *部分可以针对不同类型的数据执行不同的操作。


对于真正的二进制文件,不应使用readlines函数。数据中的任何换行都是偶然的,因此您不希望使用它们来拆分文件。然而,查看readlines函数的想法很好 - 但是你必须调整你从中学到的东西,而不是从中复制。我假设它是一个生成器函数,这是一个很酷的主意,并且可以记住从函数调用到下一个函数的各种状态。但是因为你只需要记住你在文件中的位置,这种事情可以起作用并且更容易理解(但是时间效率要低一点)。

答案 2 :(得分:0)

如果您的文件是二进制数据,并且它只是几兆字节,您可能希望立即阅读整个文件。这就是您现在正在使用didson_file.read()

如果文件是文本数据,按行组织,有一个很好的习惯用法可以方便地一次处理一行:

with open("my_file_name") as f:
    for line in f:
        do_something_with_line(line)

实际上,由于你需要解析那些结构,很明显你正在读取二进制文件。在这种情况下,你应该啜饮整个事情(如果内存使用不是问题),或者以块的形式读取它(更复杂,但会降低内存使用率)。