带信息头.dat转.csv过程记录

组里面做脑电采集了一些数据,数据以.dat文件存储,比较杂乱,数据形式为:

  • 第一部分:信息行。以类似字典(dict)的形式存储,只占用1行,按位计算列数500以上。实际上读取时会读取为str型,需要在取出后转为dict
  • 第二部分:数据体。以空格为分隔符,每行4个数值,float类型。行数不定。取出后也需从str列表转为float列表
  • 第三部分:参数行。与第一部分类似,在数据体后面,由于格式化不佳,可能会占用多行,按位计算列数1000以上

下面对每一部分进行记录

1.采用的包和地址准备:

import csv
import os
import json

input_file_dir = 'D:\\Desktop\\脑电机器1\\dat\\'
output_file_dir = 'D:\\Desktop\\脑电机器1\\csv\\'

2.读取信息头

记input_file为输入的文件,以utf-8-sig编码打开文件,后续以同样方式写入,用readlines()按行读取为一个列表

    fr = open(input_file, encoding='utf-8-sig', errors='ignore')
    array = fr.readlines()

    # 读取信息头
    str_mat = array[0]  # 取出字符串格式的字典
    # print(type(str_mat))
    dict_mat = json.loads(str_mat)
    with open(file=output_file, mode='w', newline='', encoding='utf-8-sig') as f:
        writer = csv.DictWriter(f, fieldnames=dict_mat.keys())
        writer.writeheader()
        writer.writerow(dict_mat)

取出第一行,使用json.loads()将读出的str类型列表,转换为字典(注意!此列表在写入时已经满足了字典的格式,如:{"a":A, "b": B})

使用csv.DictWriter()向csv文件中写入字典格式的数据,writer.writerow()表示向输出文件中按行写入,另外,采用with open是为了简化掉最后的close环节

3.读取数据体

由于数据体的行数不确定,因此定义了data_length作为数据区的截止行数(注意是截止时的行数,不是数据区的行数)注意到每个文件都有一行信息头,因此数据体实际是从第二行开始的。这里采用了 计算最后的参数有多少行 来计算数据体的行数,用param_lines记录参数或信息行数。这里是采取了一点投机取巧的方式,由于数据体列数只有15列左右,而前后的参数行和信息头的列数都在数百以上,因此以列数作为判断方式,超过100即为参数行或信息头

分类了三种情况:末尾参数仅1行(param_lines=1, 正常情况NORMAL)、末尾参数2行及以上(param_lines>=2, 末尾多参数行MULTI_PARAM)、末尾没有参数行(param_lines=0, NO_PARAM),利用isNormal来记录情况。

    # 读取数据区
    # 数据区结束后最多出现了两排参数
    # 因此需要特别读取数据区长度
    # 正常情况
    length = len(array)
    isNormal = "NORMAL"
    # 计算参数行数量
    param_lines = 0  # 参数行初始化
    for row in range(0, length):
        if len(array[row]) > 100:
            param_lines += 1

    # 数据情况标注
    # 注意至少有一行参数行,即第一行
    data_length = 0  # 初始化数据区截止行数
    if param_lines >= 3:  # 判断倒数第二行是否为参数
        data_length = length - param_lines + 1  # 注意第一行也被计算进去,多减了需要加1
        isNormal = "MULTI_PARAM"
    elif param_lines == 1:
        data_length = length
        isNormal = "NO_PARAM"
    elif param_lines == 2:
        data_length = length - param_lines + 1
        isNormal = "NORMAL"
    for row in range(1, data_length):
        data_mat1 = array[row]
        data_str_list = data_mat1.split()
        # print(data_str_list)
        # print(type(data_str_list))
        data_float_list = list(map(float, data_str_list))
        with open(file=output_file, mode='a', newline='') as f:
            writer = csv.writer(f)
            # writer.writeheader()
            writer.writerow(data_float_list)

NORMAL和MULTI_PARAM情况下,数据体的截止行:总行数-参数&信息行数(param_lines)+1(注意是从0开始计);在NO_PARAM情况下,数据体的截止行就是文件最后一行。可以考虑合并优化这一部分代码,但为了贴合数据本身情况,写成了三种情况。

数据用.split()函数进行分隔,输出为列表。

4.读取参数行

读取参数行时,虽然看上去数据已经按照字典格式写好了,但是读取出来实际上是str型,需要进行转换。采用json.loads()即可将已经格式化好的str类型列表转换为字典。注意写入时open函数的mode应为'a'

在NORMAL情况下,末尾的参数行应该只有一行,所以取出最后一行即可;在MULTI_PARAM情况下,注意初始化存储用的字典列表dict_mat()={},从参数行开始行的序数(注意从0开始计)即总行数-参数&信息行+1 到 总行数-1,遍历所有参数行进行写入,用.update()将字典列表取出为单独的字典格式(这里update实际上最初是合并&更新字典的作用);在NO_PARAM情况下,直接跳出函数。

    # 读取参数区
    str_mat_array = {}  # 存储字符串格式的字典
    dict_mat_array = {}  # 存储字典
    if isNormal == "NORMAL":
        str_mat = array[length - 1]  # 取出字符串格式的字典
        # print(str_mat)
        dict_mat = json.loads(str_mat)
        # print(dict_mat)
        with open(file=output_file, mode='a', newline='', encoding='utf-8-sig') as f:
            writer = csv.DictWriter(f, fieldnames=dict_mat.keys())
            writer.writeheader()
            writer.writerow(dict_mat)
    elif isNormal == "MULTI_PARAM":
        i = 0
        dict_mat = {}
        for row in range(length-param_lines+1, length-1):
            str_mat_array[i] = array[row]
            # print(str_mat_array[i])
            dict_mat_array[i] = json.loads(str_mat_array[i])
            dict_mat.update(dict_mat_array[i])
            i += 1
            with open(file=output_file, mode='a', newline='', encoding='utf-8-sig') as f:
                writer = csv.DictWriter(f, fieldnames=dict_mat.keys())
                writer.writeheader()
                writer.writerow(dict_mat)
    elif isNormal == "NO_PARAM":
        return True

5.完整代码

以上的部分合并为函数dat2csv(,),并加入对文件的批处理,完整代码如下

import csv
import os
import json

input_file_dir = 'D:\\Desktop\\脑电机器1\\dat\\'
output_file_dir = 'D:\\Desktop\\脑电机器1\\csv\\'


def dat2csv(input_file, output_file):
    """
    data转csv核心函数
    :param input_file: 输入文件全名
    :param output_file: 输出文件全名
    :return:
    """
    fr = open(input_file, encoding='utf-8-sig', errors='ignore')
    array = fr.readlines()

    # 读取信息头
    str_mat = array[0]  # 取出字符串格式的字典
    # print(type(str_mat))
    dict_mat = json.loads(str_mat)
    with open(file=output_file, mode='w', newline='', encoding='utf-8-sig') as f:
        writer = csv.DictWriter(f, fieldnames=dict_mat.keys())
        writer.writeheader()
        writer.writerow(dict_mat)

    # 读取数据区
    # 数据区结束后最多出现了两排参数
    # 因此需要特别读取数据区长度
    # 正常情况
    length = len(array)
    isNormal = "NORMAL"
    # 计算参数行数量
    param_lines = 0  # 参数行初始化
    for row in range(0, length):
        if len(array[row]) > 100:
            param_lines += 1

    # 数据情况标注
    # 注意至少有一行参数行,即第一行
    data_length = 0  # 初始化数据区截止行数
    if param_lines >= 3:  # 判断倒数第二行是否为参数
        data_length = length - param_lines + 1  # 注意第一行也被计算进去,多减了需要加1
        isNormal = "MULTI_PARAM"
    elif param_lines == 1:
        data_length = length
        isNormal = "NO_PARAM"
    elif param_lines == 2:
        data_length = length - param_lines + 1
        isNormal = "NORMAL"
    for row in range(1, data_length):
        data_mat1 = array[row]
        data_str_list = data_mat1.split()
        # print(data_str_list)
        # print(type(data_str_list))
        data_float_list = list(map(float, data_str_list))
        with open(file=output_file, mode='a', newline='') as f:
            writer = csv.writer(f)
            # writer.writeheader()
            writer.writerow(data_float_list)

    # 读取参数区
    str_mat_array = {}  # 存储字符串格式的字典
    dict_mat_array = {}  # 存储字典
    if isNormal == "NORMAL":
        str_mat = array[length - 1]  # 取出字符串格式的字典
        # print(str_mat)
        dict_mat = json.loads(str_mat)
        # print(dict_mat)
        with open(file=output_file, mode='a', newline='', encoding='utf-8-sig') as f:
            writer = csv.DictWriter(f, fieldnames=dict_mat.keys())
            writer.writeheader()
            writer.writerow(dict_mat)
    elif isNormal == "MULTI_PARAM":
        i = 0
        dict_mat = {}
        for row in range(length-param_lines+1, length-1):
            str_mat_array[i] = array[row]
            # print(str_mat_array[i])
            dict_mat_array[i] = json.loads(str_mat_array[i])
            dict_mat.update(dict_mat_array[i])
            i += 1
            with open(file=output_file, mode='a', newline='', encoding='utf-8-sig') as f:
                writer = csv.DictWriter(f, fieldnames=dict_mat.keys())
                writer.writeheader()
                writer.writerow(dict_mat)
    elif isNormal == "NO_PARAM":
        return True


def data2csv_batch_proc(filedir):
    """
    data转csv批处理函数
    :param filedir: 读取文件路径
    :return:
    """
    filelist = os.listdir(filedir)
    print(filelist)
    # file:文件名
    for file in filelist:
        # 设置输入文件地址
        print(file)
        input_file = input_file_dir + file
        # 设置输出文件名
        output_file_name = file[:22] + '.csv'
        # 设置输出文件地址
        output_file = output_file_dir + output_file_name

        dat2csv(input_file, output_file)


data2csv_batch_proc(input_file_dir)

输入的dat文件示例截图:(已将敏感信息抹除,仅展示极小部分初始待机数据)

输出的csv文件示例截图:(仅展示极小部分,未展示敏感信息)

博主代码能力较弱,字符代号有些混乱,请稍见谅。效果不佳,仅作方案记录。

  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ソセン

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值