使用Python,如何从具有多个可变长度记录的二进制数据文件中读取和提取数据?

ljt*_*ljt 3 python gps binary-data

使用Python(3.1或2.6),我试图从GPS接收器生成的二进制数据文件中读取数据.每小时的数据存储在一个单独的文件中,每个文件大约18 MiB.数据文件有多个可变长度记录,但是现在我需要从其中一个记录中提取数据.

我已经有了能够解码头部的程度.我有点说,因为有些数字没有意义,但大多数都没有.花了几天时间(我开始学习使用Python编程),我没有取得进展,所以是时候寻求帮助了.

参考指南为我提供了消息头结构和记录结构.标头长度可变,但通常为28个字节.

Header
Field #  Field Name    Field Type    Desc                 Bytes    Offset
1        Sync          char          Hex 0xAA             1        0
2        Sync          char          Hex 0x44             1        1
3        Sync          char          Hex 0x12             1        2
4        Header Lgth   uchar         Length of header     1        3
5        Message ID    ushort        Message ID of log    2        4
8        Message Lgth  ushort        length of message    2        8
11       Time Status   enum          Quality of GPS time  1        13
12       Week          ushort        GPS week number      2        14
13       Milliseconds  GPSec         Time in ms           4        16


Record
Field #  Data                        Bytes         Format     Units       Offset
1        Header                                                           0
2        Number of SV Observations   4             integer    n/a         H
         *For first SV Observation*  
3        PRN                         4             integer    n/a         H+4
4        SV Azimuth angle            4             float      degrees     H+8
5        SV Elevation angle          4             float      degrees     H+12
6        C/N0                        8             double     db-Hz       H+16
7        Total S4                    8             double     n/a         H+24
...
27       L2 C/N0                     8             double     db-Hz       H+148
28       *For next SV Observation*
         SV Observation is satellite - there could be anywhere from 8 to 13 
         in view.
Run Code Online (Sandbox Code Playgroud)

这是我试图理解标题的代码:

import struct

filename = "100301_110000.nvd"

f = open(filename, "rb")
s = f.read(28)
x, y, z, lgth, msg_id, mtype, port, mlgth, seq, idletime, timestatus, week, millis,    recstatus, reserved, version = struct.unpack("<cccBHcBHHBcHLLHH", s)

print(x, y, z, lgth, msg_id, mtype, port, mlgth, seq, idletime, timestatus, week, millis, recstatus, reserved, version)
Run Code Online (Sandbox Code Playgroud)

它输出:

b'\xaa' b'D' b'\x12' 28 274 b'\x02' 32 1524 0 78 b'\xa0' 1573 126060000 10485760 3545 35358
Run Code Online (Sandbox Code Playgroud)

3个同步字段应返回xAA x44 x12.(D是x44的ascii等价 - 我假设.)

我正在寻找的记录ID是274 - 这似乎是正确的.

GPS周返回为1573 - 这似乎是正确的.

毫秒返回为126060000 - 我期待126015000.

如何查找标识为274的记录并将其提取出来?(我正在学习Python和编程,所以请记住,你给经验丰富的程序员提供的答案可能超出我的想法.)

S.L*_*ott 6

你必须阅读.不是因为内存限制,而是因为解析要求.18MiB很容易适合记忆.在4Gb机器上,它适合内存200次.

这是通常的设计模式.

  1. 仅读取前4个字节.使用struct解压只是那些字节.确认同步字节并获取标头长度.

    如果你想要标题的其余部分,你知道长度,读取其余的字节.

    如果您不想要标题,请使用seek跳过它.

  2. 读取记录的前四个字节以获得SV观察的数量.使用struct将它解开.

    进行数学运算并读取指定的字节数,以获得记录中的所有SV观测值.

    打开包装,做你正在做的任何事情.

    我强烈建议namedtuple在对数据进行任何其他操作之前从数据中构建对象.

如果您想要所有数据,则必须实际读取所有数据.

"并且一次只读取一个字节的18 MiB文件?" 我不明白这个约束.您必须读取所有字节才能获得所有字节.

您可以使用长度信息来读取有意义块中的字节.但你无法避免阅读所有字节.

此外,许多读取(和搜索)通常足够快.您的操作系统缓冲区,所以不要担心尝试微量优化读取次数.

只需按照"读取长度 - 读取数据"模式即可.