【问题标题】:Importing .dat files in python without knowing how it is structured在不知道其结构的情况下在 python 中导入 .dat 文件
【发布时间】:2021-03-18 07:07:02
【问题描述】:

我正在尝试加载并查看可以从here 下载的数据内容。之后我需要对其进行分析。对此,我已经posed on problem了,但没有得到任何解决方案。

现在,我浏览了他们位于here 的标签文件。其中提到了

“将编写有用的基于 Python 的字母来描述每个对象
/ /请参阅 http://docs.python.org/library/struct.html 的代码/ / 格式将以逗号分隔以“RJW, " 作为键然后 / / {NAME}, {FORMAT}, {Number of dims}, {Size Dim 1}, {Size Dim 2}, ... / / 其中 {FORMAT} 是该类型的 Python 代码,即 I 对于 uint32 //,Size Dim 的数量与 方面。 ”

所以,我想可以尝试一下 python。我确实有python的工作知识。所以,我从here 获得的这个程序开始(为简单起见,python 文件和数据文件在同一个文件夹中):

import numpy as np
data = np.genfromtxt('JAD_L30_LRS_ELC_ANY_CNT_2018091_V03.dat')
print(data)

我收到了错误“UnicodeDecodeError: 'cp949' codec can't decode byte 0xff in position 65: illegal multibyte sequence”.

如果我将代码更改为(as mentioned here):

data=open('JAD_L30_LRS_ELC_ANY_CNT_2018091_V03.DAT', encoding='utf-8')
print(data)

错误消息消失了,但我得到的只是:

<_io.TextIOWrapper name='JAD_L30_LRS_ELC_ANY_CNT_2018091_V03.DAT' mode='r' encoding='utf-8'>

我在 StackOverflow 中检查了其他答案,但没有得到任何答案。我的问题可能与here 发布的内容非常相似

我需要先查看这个 dat 文件的内容,然后导出为其他格式,比如 .csv。

任何帮助将不胜感激...

【问题讨论】:

  • 您需要在使用open(...) 返回的内容上调用.read(),以便读取文件的内容以查看数据文件中的内容。你得到的是一个repr 输出告诉你data 是一个TextIOWrapper

标签: python import


【解决方案1】:

您需要以二进制模式打开文件。

with open('JAD_L30_LRS_ELC_ANY_CNT_2018091_V03.DAT', 'rb') as f:
    while True:
        chunk = f.read(160036) # that is record size as per LBL file
            # because the file is huge it will expect to hit Enter
            # to display next chunk. Use Ctrl+C to interrupt
        print(chunk)
        input('Hit Enter...')

注意,您可以解析 LBL 文件,构造格式字符串以与 struct 模块一起使用,并将每个块解析为有意义的字段。这就是您引用的评论的意思。

"""Example of reading NASA JUNO JADE CALIBRATED SCIENCE DATA
https://pds-ppi.igpp.ucla.edu/search/view/?f=yes&id=pds://PPI/JNO-J_SW-JAD-3-CALIBRATED-V1.0/DATA/2018/2018091/ELECTRONS/JAD_L30_LRS_ELC_ANY_CNT_2018091_V03&o=1
https://stackoverflow.com/a/66687113/4046632
"""

import struct
from functools import reduce
from operator import mul
from collections import namedtuple

__author__ = "Boyan Kolev, https://stackoverflow.com/users/4046632/buran"

with open('JAD_L30_LRS_ELC_ANY_CNT_2018091_V03.LBL') as f:
    rjws = [line.strip('\n/* ') for line in f if line.startswith('/* RJW')]

# create the format string for struct
rjws = rjws[2:] # exclude first 2 RJW comments related to file itself
names = []
FMT = '='
print(f'Number of objects: {len(rjws)}')
for idx, rjw in enumerate(rjws):
    _, name, fmt, num_dim, *dims = rjw.split(', ')
    fstr = f'{reduce(mul, map(int, dims))}{fmt}'
    FMT = f'{FMT} {fstr}'
    names.append(name)
    print(f'{idx}:{name}, {fstr}')
FMT = FMT.replace('c', 's') # for conveninece treat 21c as s char[]
print(f"Format string: {repr(FMT)}")

# parse DAT file
s = struct.Struct(FMT)
print(f'Struct size:{s.size}')
with open('JAD_L30_LRS_ELC_ANY_CNT_2018091_V03.DAT', 'rb') as f:
    n = 0
    while True: # in python3.8+ this loop can be simplified with walrus operator
        chunk = f.read(s.size)
        if not chunk:
            break
        data = s.unpack_from(chunk)
        # process data further, e.g. split data in 2D containers where appropriate
        n += 1

print(f'Number of records: {n}')

# make a named tuple to represent first 10 fields
# for nice display. This basic use of namedtuple works only
# for first 23 objects, which have single item.
num_fields = 10
Record = namedtuple('Record', names[:num_fields])
record = Record(*data[:num_fields])
print('\n----------------------\n')
print(f'First {num_fields} fields of the last record.')
print(record)

输出:

Number of objects: 49
0:DIM0_UTC, 21c
1:PACKETID, 1B
2:DIM0_UTC_UPPER, 21c

--- omitted for sake of brevity ---

46:DIM2_AZIMUTH_DESPUN_LOWER, 3072f
47:MAG_VECTOR, 3f
48:ESENSOR, 1H
Format string: '= 21s 1B 21s 1b 21s 1b 1H 1B 1B 1B 1B 1h 1h 1f 1f 1f 1f 1f 1f 1f 1f 1f 1f 3f 3f 3f 1f 9f 9f 9f 1f 1I 1I 1H 3072f 3072f 3072f 3072f 3072f 3072f 3072f 3072f 3072f 3072f 3072f 3072f 3072f 3f 1H'
Struct size:160036
Number of records: 1101

----------------------

First 10 fields of the last record.
Record(DIM0_UTC=b'2018-091T23:56:08.925', PACKETID=106, DIM0_UTC_UPPER=b'2018-092T00:01:08.925', PACKET_MODE=1, DIM0_UTC_LOWER=b'2018-091T23:51:08.925', PACKET_SPECIES=-1, ACCUMULATION_TIME=600, DATA_UNITS=2, SOURCE_BACKGROUND=3, SOURCE_DEAD_TIME=0)

链接到GutHub gist

【讨论】:

  • 非常感谢这段精彩的代码。我试图理解它,但似乎它正在完成这项工作。正如我在问题中提到的,是否可以将其导出到 .csv 文件中,其中包含列'DIM0_UTC、PACKETID、....、MAG_VECTOR、ESENSOR' 和具有相应值的行?由于这是一种整理,你也可以看看这个问题[stackoverflow.com/questions/59782618/….
  • 您始终可以保存在 csv 中,但有 40004 个单独的字段。根据描述,有二维数据容器(全部为 3072 = 64 * 48 )。所以你需要决定如何处理它。顺便说一下,您在另一个问题中提到的 NASA 查看器显示了 39996 列,但对于一些 1D 但有 3 个项目的对象,例如 SC_POS_JUPITER_J2000XYZ 它只显示 1 个值。
  • 感谢您的快速回复。除了 SC_POS_JUPITER_J2000XYZ 之外,其他有 3 个分量的量是 SC_VEL_JUPITER_J2000XYZ、SC_VEL_ANGULAR_J2000XYZ、MAG_VECTOR。我想,它是一种矢量。所以,如果我们考虑剩余的 6 列,我们得到 40004 (=39996+6)。我检查了上一个问题中提到的软件,但找不到导出数据值的方法。
  • 是的,这 4 个占 8 列的差异。我没有检查它如何显示 DESPUN_SC_TO_J2000、2000_TO_JSSXYZ 和 J2000_TO_JSSRTP,它们都是 9 项 !D 对象,但我猜它是文件。此外,我编辑了我的答案,包括评论 namedtuple 的这种基本用法仅适用于前 23 个对象,这些对象具有单个项目。是的,我也认为 NASA 软件只是查看器,没有导出选项。
猜你喜欢
  • 1970-01-01
  • 2018-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多