linux-Ubuntu server输出.csv文件方法 小结

导语:

  在ARM上或在其他芯片上做开发,有时候会有这样的需求,将你工控机、开发板或者你的设备采集出来的数据做成一个exc列表;最简单的方式就是用数据直接输出为.txt文件,但是这样并不方便wps或者Excel表格打开;

常用的一个方式就是生成.csv文件;这是大多数上位机采取的一种数据存根的方式;对某些场合的使用是非常便利!

接下来总结在ARM板上实现的,对数据生成.csv的操作;其他的平台,方式类同;

1.csv文件生成接口

普及一下:.csv文件格式要求--百度百科https://baike.baidu.com/item/CSV/10739?fr=aladdin

/root__/business   (代码位置)
       |__/flow        (流水位置-有coout索引和.csv文件)

操作过程,一完整的数据到了,先查询上次写入到哪一个文件哪一条流水,比如是第1个文件的第100条(最大数),此次立马写入第2个文件第一条(第0条并补上第0条的标题);如果写到第1个文件的第23条,那么该次流水应该写第1个文件的第24条(不需要补充标题);写完后里面更新文件和流水索引--以便下次查询;

/****************************************************
* 函数名:create_flow
* 功能描述:生成流水
* 输入参数:流水原始的数据
* 输出参数:
* 返回值:
* 备注:
****************************************************/
void VCBusiness::create_flow(const OBU_OBJECT_STRU *obu_object) {
    if (NULL == obu_object) {
        LOG_ERROR("func:%s : 指针为NULL", __func__);
        return;
    }

    u16 file_index = 0, flow_index = 0;
    char file_name[64] = {0};
    string write_str;
    char write_head[1024] = {0};
    char temp[32] = {0};
    FILE *fp = NULL;
    u16 trans_time = GET_INTERVAL_TIME(obu_object->life_time);
    /* 获取索引 */
    get_flow_file_index(&flow_index, &file_index);
    /* 根据索引指定记录文件 */
    sprintf(file_name, "/root/flow/flow_file_%05d.csv", file_index);
    /* 打开记录文件 */
    fp = fopen(file_name, "a+");
    if (NULL == fp) {
        LOG_WARN("[%s]打开文件失败", __func__);
        return;
    }
    /* 未记录过文件 */
    if (0 == flow_index) {
        //sprintf(write_head, "TransResult,ErrorCode,TransTime,TAC,PSAMTradeNum,FlagNo,RsuNo,DevType,ObuId,OBUProvider,ContractType,CPC EF02,OBUSerialNum,OBUStartTime,OBUEndTime,OBUStatus,VehClass,VehPlate,VehPlateColor,CardProvider,CPUCardType,CardVersion,CardNetWork,CardId,CardStartTime,CardEndTime,TerminalId,TotalTime\n");
        sprintf(write_head, "TransResult,ErrorCode,TransTime,TAC,PSAMTradeNum,FlagNo,RsuNo,DevType,ObuId,OBUProvider,E-WalletTradeNum ,CPC EF02,OBUSerialNum,OBUStartTime,OBUEndTime,OBUStatus,VehClass,VehPlate,VehPlateColor,CardProvider,CPUCardType,CardVersion,CardNetWork,CardId,CardStartTime,CardEndTime,TerminalId,TotalTime\n");
        fwrite(write_head, sizeof(char), strlen(write_head), fp);
    }
	/********************开始组.csv文件内容**********************************************************************/
    bytes_to_hex_string(&write_str, &obu_object->transresult, 1);			//保存原来的16进制,直接写入
		......
    //bytes_to_hex_string(&write_str, obu_object->obu_flow_info.vehicle_info_stru.VehicleLicencePlateColor_Pack, 2);
    memcpy(temp, obu_object->obu_flow_info.vehicle_info_stru.VehicleLicencePlateColor_Pack, 2);//对hex转ascii,汉字写入
    write_str.append(temp, 2);
	memset(temp, 0, sizeof(temp));
    sprintf(temp, ",");  write_str.append(temp);
		......
    /* CardEndTime */
    bytes_to_hex_string(&write_str, obu_object->obu_flow_info.iccard_info_stru.issuerinfo + 24, 4);
    /* TerminalId */
    bytes_to_hex_string(&write_str, obu_object->obu_flow_info.trade_info_stru.TerminalID, 6);
    /* TotalTime */
    sprintf(temp, "%08x\n", trans_time);//最后一个变量,不需要补逗号,直接追加打印
    write_str.append(temp);
	/*******************组.csv文件内容结束***********************************************************************/
    /* 写入文件 */
    fwrite(write_str.c_str(), sizeof(char), write_str.length(), fp);
    fclose(fp);
    /* 更新索引 */
    if (flow_index >= FLOW_COUNT_PER_FILE_MAX) {
        flow_index = 0;
        file_index++;
    } else {
        flow_index++;
    }
    set_flow_file_index(flow_index, file_index);
}

2.开头的查询和结尾的更新索引操作

/****************************************************
* 函数名:get_flow_file_index
* 功能描述:获取流水数据的存储索引
* 输入参数:
* 输出参数:file_index-当前流水文件索引, flow_index-单个文件流水索引
* 返回值:
* 备注:避免单文件太大,所以会生成多个文件,故有文件索引号1,2,3,4...
* 备注:为方便浏览和传输,每个文件都存100条流水,故流水索引号1,2..100
****************************************************/
bool VCBusiness::get_flow_file_index(u16 *flow_index, u16 *file_index) {
    system("touch /root/flow/countor");//创建文件的个数,为避免单个文件太大
    /* 流水文件编号 */
    auto file_count = ConfDataParsor::GetValue("FILE_COUNT", flow_countor_path);
    if (!file_count.success) {
        *file_index = 0;
		LOG_DEBUG("[%s][%d]", __func__, __LINE__);
    } else {
        *file_index = atoi(file_count.data);//获得上次最新的文件索引
    }
    /* 流水编号 */
    auto flow_count = ConfDataParsor::GetValue("FLOW_COUNT", flow_countor_path);
    if (!flow_count.success) {
        *flow_index = 0;
		LOG_DEBUG("[%s][%d]", __func__, __LINE__);
    } else {
        *flow_index = atoi(flow_count.data);//获得上次产生的最新的流量序号,100条流水打包为一个文件
    }
}
/****************************************************
* 函数名:set_flow_file_index
* 功能描述:设置流水存储索引
* 输入参数:file_index-流水文件索引, flow_index-单个文件流水索引
* 输出参数:
* 返回值:
* 备注:
****************************************************/
void VCBusiness::set_flow_file_index(u16 flow_index, u16 file_index) {
    system("touch /root/flow/countor");

    /* 流水文件编号 */
    if (false == ConfDataParsor::SetValue("FILE_COUNT", flow_countor_path, file_index)) {
        LOG_WARN("[%s]设置流水文件编号失败", __func__);
    }
    /* 文件内流水编号 */
    if  (false == ConfDataParsor::SetValue("FLOW_COUNT", flow_countor_path, flow_index)) {
        LOG_WARN("[%s]设置流水编号失败", __func__);
    }
}

3.中间的的数据存储说明

//如果是16进制-hex追加的话可以用sprintf(temp, "%02x", data[i]);string->append(temp);
//如果需要追加汉字则需要,sprintf(temp,"黄色");再追加string->append(temp);
//追加逗号是.csv的文件要求
void VCBusiness::bytes_to_hex_string(string *string, const u8 *data, u16 len) {
    char temp[10] = {0};
    for (int i = 0; i < len; ++i) {
        sprintf(temp, "%02x", data[i]);
        string->append(temp);
    }
    sprintf(temp, ",");
    string->append(temp);
}

4.最后用wps或excel打开的效果如图-供参考

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

xiaoxilang

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

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

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

打赏作者

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

抵扣说明:

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

余额充值