在python中读取二进制数据

J W*_*J W 7 python binary file

首先,在此问题被标记为重复之前,我知道其他人已经提出类似的问题,但似乎没有明确的解释.我正在尝试将二进制文件读入二维数组(在此处有详细记录http://nsidc.org/data/docs/daac/nsidc0051_gsfc_seaice.gd.html).

标头是一个300字节的数组.

到目前为止,我有;

import struct

with open("nt_197912_n07_v1.1_n.bin",mode='rb') as file:
    filecontent = file.read()

x = struct.unpack("iiii",filecontent[:300])
Run Code Online (Sandbox Code Playgroud)

抛出字符串参数长度的错误.

Jam*_*han 5

阅读数据(简答)

从标题中确定网格的大小(n_rowsx n_cols= 448x304)后(见下文),您可以使用简单的数据读取数据numpy.frombuffer.

import numpy as np

#...

#Get data from Numpy buffer
dt = np.dtype(('>u1', (n_rows, n_cols)))
x = np.frombuffer(filecontent[300:], dt) #we know the data starts from idx 300 onwards

#Remove unnecessary dimension that numpy gave us
x = x[0,:,:]
Run Code Online (Sandbox Code Playgroud)

'>u1'指定数据的格式,在这种情况下无符号的大小为1字节的整数,是big-endian格式.

用此绘图 matplotlib.pyplot

import matplotlib.pyplot as plt

#...

plt.imshow(x, extent=[0,3,-3,3], aspect="auto")
plt.show()
Run Code Online (Sandbox Code Playgroud)

extent=选项只是指定轴值,您可以将它们更改为lat/lon(例如从标题中解析)

产量

.unpack()中的错误说明

来自以下文档struct.unpack(fmt, string):

该字符串必须包含格式所需的数据量(len(string)必须相等calcsize(fmt))

您可以fmt通过查看" 格式字符"部分来确定格式字符串()中指定的大小.

你的fmtin struct.unpack("iiii",filecontent[:300]),指定4个int类型(为了简单起见你也可以使用4i= iiii),每个类型的大小为4,需要一个长度为16的字符串.

你的字符串(filecontent[:300])长度为300,而你fmt要求长度为16的字符串,因此错误.

.unpack()的示例用法

例如,读取提供的文档我提取了前21*6个字节,其格式为:

包含6字节字符串的21个元素的数组,包含极性立体网格特征等信息

附:

x = struct.unpack("6s"*21, filecontent[:126])
Run Code Online (Sandbox Code Playgroud)

这将返回21个元素的元组.请注意某些元素中的空白填充符合6字节要求.

>> print x
    # ('00255\x00', '  304\x00', '  448\x00', '1.799\x00', '39.43\x00', '45.00\x00', '558.4\x00', '154.0\x00', '234.0\x00', '
    # SMMR\x00', '07 cn\x00', '  336\x00', ' 0000\x00', ' 0034\x00', '  364\x00', ' 0000\x00', ' 0046\x00', ' 1979\x00', '  33
    # 6\x00', '  000\x00', '00250\x00')
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 第一个参数fmt,"6s"*21是一个字符串,6s重复21次.每个格式字符6s代表一个6字节的字符串(见下文),这将匹配文档中指定的所需格式.
  • 数字126in filecontent[:126]计算为6*21 = 126.
  • 请注意,对于s(字符串)说明符,前面的数字并不意味着重复格式字符6次(正如其他格式字符一样).相反,它指定字符串的大小.s表示1字节的字符串,同时6s表示6字节的字符串.

更广泛的标题阅读解决方案(长期)

因为必须手动指定二进制数据,所以在源代码中这可能很繁琐.您可以考虑使用一些配置文件(如.ini文件)

此函数将读取标头并将其存储在字典中,其中结构由.ini文件提供

# user configparser for Python 3x
import ConfigParser

def read_header(data, config_file):
    """
    Read binary data specified by a INI file which specifies the structure
    """

    with open(config_file) as fd:

        #Init the config class
        conf = ConfigParser.ConfigParser()
        conf.readfp(fd)

        #preallocate dictionary to store data
        header = {}

        #Iterate over the key-value pairs under the
        #'Structure' section
        for key in conf.options('structure'):

            #determine the string properties
            start_idx, end_idx = [int(x) for x in conf.get('structure', key).split(',')]
            start_idx -= 1 #remember python is zero indexed!
            strLength = end_idx - start_idx

            #Get the data
            header[key] = struct.unpack("%is" % strLength, data[start_idx:end_idx])

            #Format the data
            header[key] = [x.strip() for x in header[key]]
            header[key] = [x.replace('\x00', '') for x in header[key]]

        #Unmap from list-type
        #use .items() for Python 3x
        header = {k:v[0] for k, v in header.iteritems()}

    return header
Run Code Online (Sandbox Code Playgroud)

.ini下面的示例文件.键是存储数据时使用的名称,值是逗号分隔的值对,第一个是起始索引,第二个是结束索引.这些值取自您文档中的表1.

[structure]
missing_data: 1, 6
n_cols: 7, 12
n_rows: 13, 18
latitude_enclosed: 25, 30
Run Code Online (Sandbox Code Playgroud)

该功能可以使用如下:

header = read_header(filecontent, 'headerStructure.ini')
n_cols = int(header['n_cols'])
Run Code Online (Sandbox Code Playgroud)