当前位置: 首页 > news >正文

基于Linux文件编程实现处理Excel表格的数据

目录

前言

整体的代码框架

如何读取数据文件的数据

read_line

如何处理读取到的数据

process_data

运行结果

总结


前言

        本文是基于Linux文件编程的一个小实验,用文件IO来读取Excel表格的数据,处理后写入另一个文件,本文只是对文件IO的基本应用,巩固文件编程的知识。Linux一切皆文件。本文的侧重点是对于数据的处理。

(图1) 

来看这个简单的表格,要计算三人的总分,对于熟练应用Excel表格的人来说很简单,在 E2 输入计算公式 =sum(b2:d2) 然后下拉就能计算三人的总分;如果再加上一个评分栏,根据总分给每个人评级,对于不熟悉Excel的人来说就有点难了,但我们可以通过编程实现这个功能。

(上图为最终实现的效果,将图1的Excel文件另存为 .csv 格式) 

 .csv格式是用逗号分割的文件,用记事本打开可以看到第一行的数据为",语文,数学,英语,总分,评价",之所以第一个字符是逗号,是因为表格的第一行第一列为空,csv格式会用逗号分隔每个数据,“总分”和“评价”那一列也没有数据,但是空出来的数据之间也有逗号分隔开,将score.csv文件上传到虚拟机,就可以开始编写代码了。


整体的代码框架

对于Linux文件编程不了解的,可以看我之前的博客Linux文件编程,里面有详细的函数介绍和代码示例。

我们只需要用三个函数:
open函数

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

read函数

#include <unistd.h>ssize_t read(int fd, void *buf, size_t count);

write函数

#include <unistd.h>ssize_t write(int fd, const void *buf, size_t count);

整体的函数框架

\bullet 打开数据文件

\bullet 创建结果文件

\bullet 在while循环里
        \circ 读取一行的数据
        \circ 处理数据
        \circ 写入结果文件

\bullet 最后关闭文件

以上就是整个程序的大致框架,现在来写程序,难点还是数据的处理

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>/*打印错误信息所要包含的头文件*//* 最终编译出来的可执行文件的用法,以及main函数的参数* ./process_excel data.csv result.csv* argc    = 3* argv[0] = "./process_excel"* argv[1] = "data.csv"* argv[2] = "result.csv"*/int main(int argc, char **argv)
{/*数据文件和结果文件的文件描述符*/int fd_data, fd_result;/*记录用户自己编写的函数的返回值*/int len;/*存放从数据文件读到的数据*/unsigned char data_buf[1000];/*存放处理好即将写入结果文件的数据*/unsigned char result_buf[1000];  /*如果main函数传入的参数不对,则打印用法*/if (argc != 3){printf("Usage: %s <data.csv> <result.csv>\n", argv[0]);return -1;}/*以只读的方式打开数据文件*/fd_data = open(argv[1], O_RDONLY);if (fd_data < 0){/*打开失败就打印失败信息*/printf("can not open file %s\n", argv[1]);perror("open");return -1; }else{/*成功打开打印数据文件的文件描述符*/printf("data file fd = %d\n", fd_data);}/*可读可写方式打开(不存在就创建),截断文件,权限为0644(文件所有者具有读写权限,其他用户具有读权限)*/fd_result = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0644);if (fd_result < 0){printf("can not creat file %s\n", argv[2]);perror("creat");return -1; }else{printf("result file fd = %d\n", fd_result);}/*------------------------------------重点------------------------------------*/while(1){/*从数据文件里读取1行*/len = read_line(fd_data, data_buf);if(len == -1){	break;	}if(len != 0){/*处理数据,将处理好的数据存入result_buf*/process_data(data_buf, result_buf);/*写入结果文件,要写入的每一行数据都是不带回车换行的,需要我们自己写入*/ write(fd_result, result_buf, strlen(result_buf));write(fd_result, "\r\n", 2);}}/*养成好习惯,关闭打开的文件,避免造成损坏*/close(fd_data);close(fd_result);return 0;
}

整个看下来,思路还是比较清晰的,就是文件IO的基本应用,重点就在于main函数的while循环里,有两个函数需要我们自己编写,read_line 和 process_data ,根据read_line函数的返回值决定是否对读取到的数据进行处理。


如何读取数据文件的数据

        读取数据文件后直接拿来判断显然不现实,在每一行数据的结尾都有一个回车换行才能从下一行开始写新的数据,但这些回车换行我们看不到,我们可以将这些内容转换成十六进制的数据

在终端输入以下命令 hexdump -C score.csv 后面的是要转换的文件名,可以看到十六进制的数据

可以看到,回车换行的十六进制是 0x0d0x0a ,就是我们常用的 '\r''\n' ,现在来编写读取每一行数据的函数

read_line

/* 返回值: n 表示读到了一行的数据的个数(n >= 0)*        -1 表示读到了文件的尾部或者出错*/
static int read_line(int fd, unsigned char *buf)
{/*循环读入一个字符*//*如何判断已经读完一行?读到 0x0d , 0x0a*/	/*读到一个字符放入c*/unsigned char c;/*记录read函数的返回值*/int len;/*传入的字符串的元素指针*/int i = 0;/*根据err变量判断该函数的返回值*/int err = 0; while(1){/*read函数读取成功会返回读取到的字节数,失败返回-1*/len = read(fd, &c, 1);if(len <= 0){/*读到文件末尾或发生错误*/err = -1;break;	}else{if(c != '\n' && c != '\r'){buf[i++] = c;}else{/*碰到回车换行*/err = 0;break;}}} /*表示字符串的结束*/buf[i] = '\0'; if(err && (i == 0)){/*读到文件尾部并且一个数据都没有读到*/return -1;}else{/*返回读取到的数据的个数+1,因为我们手动添加了结束符 '\0'*/return i;}
}

这个函数还是需要点时间看的,建议结合转换后的十六进制表示的文件来看,思路会更加清晰,一直循环读取数据文件,一个字节一个字节的读

读到0x0d的时候,跳出while循环,执行 buf[i] = '\0'; 这句代码,构造出一个字符串存入data_buf里,然后去处理数据。读到0x0a也立马跳出循环,构造出一个空的字符串。


如何处理读取到的数据

直接看代码

process_data

void process_data(unsigned char *data_buf, unsigned char *result_buf)
{/*	示例1:data_buf=",语文,数学,英语,总分,评价" *  	  result_buf=",语文,数学,英语,总分,评价" *	示例2:data_buf="张三,90,91,92" *  	  result_buf="张三,90,91,92,273,A+" */ char name[100];int scores[3];int sum;char *levels[] = {"A+", "A", "B"};int level;if (data_buf[0] == 0xef) /* 对于UTF-8编码的文件,它的前3个字符是0xef 0xbb 0xbf */{/*进入这个分支是因为我们不需要处理第一行的数据*//*将data_buf文件的数据拷贝到result_buf*/strcpy(result_buf, data_buf);}else{/*用sscanf拆分字符串,第一个为%[^,],是因为如果用%s会分割失败*/sscanf(data_buf, "%[^,],%d,%d,%d,", name, &scores[0], &scores[1], &scores[2]);/*计算总分*/sum = scores[0] + scores[1] + scores[2];if (sum >= 270)level = 0;else if (sum >= 240)level = 1;elselevel = 2;/*构造字符串*/sprintf(result_buf, "%s,%d,%d,%d,%d,%s", name, scores[0], scores[1], scores[2], sum, levels[level]);}
}

处理数据就比较简单了,第一行照搬不用处理,之后用sscanf拆分数据,分类再组合就可以写入结果文件了。


运行结果

编译运行后cat一下 result.csv ,查看文件的内容,可以看到正是我们想要的效果,传回Windows看看Excel表格,非常完美。


总结

因为是一行一行的处理数据,有些小伙伴可能会疑惑,数据为什么不会被覆盖,为什么不会得到同样的数据?

我们要知道read函数的原理,你读一个字符,文件的光标就会移动一个位置,你下次再打开这个文件,他的光标位置是不变的,除非你用lseek函数来改变光标的位置,所以我们每读一行,再加上结束符'\0'就相当于一个字符串,然后立马处理数据并且写入结果文件;下次再去读数据文件,是从上一次读的位置的下一个开始读,所以才能得到一行一行的数据。

什么时候读完?
读到文件尾部就读完了,就会跳出main函数的while循环,程序结束。

相关文章:

基于Linux文件编程实现处理Excel表格的数据

目录 前言 整体的代码框架 如何读取数据文件的数据 read_line 如何处理读取到的数据 process_data 运行结果 总结 前言 本文是基于Linux文件编程的一个小实验&#xff0c;用文件IO来读取Excel表格的数据&#xff0c;处理后写入另一个文件&#xff0c;本文只是对文件IO的…...

make 程序规定的 makefile 文件的书写语法(2)

&#xff08;13&#xff09;接着开始一个更复杂的例子&#xff0c;课程的素材 2 &#xff0c;先给出书写 makefile 的框架 &#xff1a; &#xff08;14&#xff09; &#xff08;15&#xff09; 谢谢...

容器化安装jenkins稳定版长期维护版本LTS

前提已有 docker-compose和docker-ce环境&#xff0c;这里安装稳定的Lts版本即可。 选择稳定版本 这里选择LTS 稳定长期维护的版本 在docker镜像找到LTS稳定版本 部署jenkins服务 创建持久化数据目录 jenkinsdata]# pwd /data/jenkinsdata编写docker-compose文件 jenkins_…...

如何让人工智能训练更快

影响人工智能训练时间的因素 在深度学习训练中&#xff0c;训练时间的计算涉及到多个因素&#xff0c;包括 epoch 数、全局 batch size、微 batch size、计算设备数量等。下面是一个基本的公式来说明这些参数之间的关系&#xff08;注意&#xff0c;这只是一个基本的说明公式&…...

linux/ubuntu国内镜像安装gitleaks敏感信息扫描工具教程及避坑点

1、背景 利用gitleaks扫描git仓库或者文件 GitHub上有比较详细的教程&#xff0c;但是由于每个人的安装环境不同&#xff0c;坑很多&#xff0c;网上能查到的有效信息也比较少。这里就以我坑很多的环境为例&#xff0c;捋一下步骤。 GitHub - gitleaks/gitleaks: Protect an…...

JavaScript高级程序设计基础(二)

二、语言基础 2.1语法 &#xff08;简单的语法基础将在文章省略&#xff09; 2.1.1严格模式 严格模式是一种不同的 JavaScript 解析和执行模型&#xff0c;不规范写法在这种模式下会被处理 只需在脚本开头加上"use strict" 也可以单独指定一个函数在严格模式下执…...

使用Spring Boot开发自习室预定系统

开发一个自习室预定系统涉及到用户管理、自习室管理、预定管理等功能。以下是使用Spring Boot开发自习室预定系统的步骤和关键点&#xff1a; 1. 需求分析 确定系统的基本需求&#xff0c;例如&#xff1a; 用户注册和登录管理员管理自习室信息用户浏览可用自习室用户预定自…...

最近读书总结

1《More Joel on Software》读后感【2024年8月29日】 1.1 本书概要 本书讲解了如何发现优秀的IT人才&#xff0c;并把他们招聘进来&#xff1b;如何对智力密集型的IT企业&#xff08;软件企业&#xff09;进行管理&#xff0c;即最好采用情感认同法&#xff1b;对计算机大学生…...

python列表判断是否为空的三种方式

#列表是否为空判断 a[]一&#xff1a; if a:print(not null) else:print(null)二&#xff1a; b len(a) if b 0:print(null) else:print(not null)三&#xff1a; if not a:print(null) else:print(not null)运行结果&#xff1a;...

二十三种模式之原型模式(类比制作陶器更好理解一些)

1. 设计模式的分类 创建型模式(五种)&#xff1a;工厂方法模式、单例模式、抽象工厂模式、原型模式、建造者模式。 结构型模式(七种)&#xff1a;适配器模式、代理模式、装饰器模式、桥接模式、外观模式、享元模式、组合模式。 行为型模式(十一种)&#xff1a;状态模式、模板方…...

9.9日记录

1.常见排序算法的复杂度 1.快速排序 1.1快速排序为什么快 从名称上就能看出&#xff0c;快速排序在效率方面应该具有一定的优势。尽管快速排序的平均时间复杂度与“归并排序”和“堆排序”相同&#xff0c;但通常快速排序的效率更高&#xff0c;主要有以下原因。 出现最差情况…...

鸿蒙交互事件开发04——手势事件

1 概 述 手势事件是移动应用开发中最常见的事件之一&#xff0c;鸿蒙提供了一些方法来绑定手势事件。通过给各个组件绑定不同的手势事件&#xff0c;并设计事件的响应方式&#xff0c;当手势识别成功时&#xff0c;ArkUI框架将通过事件回调通知组件手势识别的结果。 …...

研1日记9

1.理解conv1d和conv2d a. 1和2处理的数据不同&#xff0c;1维数据和图像 b. 例如x输入形状为(32,19,512)时&#xff0c;卷积公式是针对512的&#xff0c;而19应该变换为参数中指定的输出通道。 2.“SE块”&#xff08;Squeeze-and-Excitation Block&#xff09;它可以帮助模…...

HAL库学习目录查询表

日期内容2024.09.11基于STM32C8T6的CubeMX&#xff1a;HAL库点亮LED2024.09.11STMCuBeMX新建项目的两种匪夷所思的问题2024.09.11STMCubeMX文件下载后会出现其他项目无法下载的问题...

pandas DataFrame日期字段数据处理

pandas DataFrame日期字段数据处理 1、pandas读取表格文件日期字段存入数据库不需要时分秒 在使用 pandas 读取表格文件,并将日期字段存入数据库时,如果你只关心日期部分而不需要时分秒,可以通过以下步骤来处理: 读取数据并转换日期字段: 首先,你需要读取你的数据,并确…...

swift:qwen2 VL 多模态图文模型lora微调swift

参考: https://swift.readthedocs.io/zh-cn/latest/Multi-Modal/qwen2-vl%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5.html 在线demo: https://colab.research.google.com/drive/16yl6Z0wxHLX3qJ5q-SIbvPn251k3r2JC?usp=sharing 安装: !git clone https://github.com/modelsc…...

Vue.js中computed的使用方法

在Vue.js中&#xff0c;computed 属性是基于它们的依赖进行缓存的响应式属性。只有当相关依赖发生改变时&#xff0c;才会重新求值。这意味着只要computed属性依赖的源数据&#xff08;如data中的属性&#xff09;没有发生变化&#xff0c;多次访问computed属性会立即返回之前的…...

python之pyecharts制作可视化数据大屏

文章目录 前言一、安装 Pyecharts二、创建 Pyecharts 图表三、设计大屏布局四、实时数据更新五、部署和展示总结前言 使用 Pyecharts 制作可视化数据大屏是一个复杂但有趣的过程,因为 Pyecharts 本身是一个用于生成 Echarts 图表的 Python 库,而 Echarts 是由百度开发的一个…...

Chrome、Edge、360及Firefox浏览器加载多个ActiveX插件的介绍

allWebPlugin简介 allWebPlugin中间件是一款为用户提供安全、可靠、便捷的浏览器插件服务的中间件产品&#xff0c;致力于将浏览器插件重新应用到所有浏览器。它将现有ActiveX控件直接嵌入浏览器&#xff0c;实现插件加载、界面显示、接口调用、事件回调等。支持Chrome、Firefo…...

裸金属服务器与云服务器的区别有哪些?

随着云计算服务的快速发展&#xff0c;云服务器与裸金属服务器则称为各大企业基础设施的两大核心选择&#xff0c;会运用在不同的场景当中&#xff0c;本文就来介绍一下裸金属服务器与云服务器的区别都有哪些吧&#xff01; 裸金属服务器相对于云服务器来说有着卓越的性能&…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql

智慧工地管理云平台系统&#xff0c;智慧工地全套源码&#xff0c;java版智慧工地源码&#xff0c;支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求&#xff0c;提供“平台网络终端”的整体解决方案&#xff0c;提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖

在Vuzix M400 AR智能眼镜的助力下&#xff0c;卢森堡罗伯特舒曼医院&#xff08;the Robert Schuman Hospitals, HRS&#xff09;凭借在无菌制剂生产流程中引入增强现实技术&#xff08;AR&#xff09;创新项目&#xff0c;荣获了2024年6月7日由卢森堡医院药剂师协会&#xff0…...

Unity中的transform.up

2025年6月8日&#xff0c;周日下午 在Unity中&#xff0c;transform.up是Transform组件的一个属性&#xff0c;表示游戏对象在世界空间中的“上”方向&#xff08;Y轴正方向&#xff09;&#xff0c;且会随对象旋转动态变化。以下是关键点解析&#xff1a; 基本定义 transfor…...

背包问题双雄:01 背包与完全背包详解(Java 实现)

一、背包问题概述 背包问题是动态规划领域的经典问题&#xff0c;其核心在于如何在有限容量的背包中选择物品&#xff0c;使得总价值最大化。根据物品选择规则的不同&#xff0c;主要分为两类&#xff1a; 01 背包&#xff1a;每件物品最多选 1 次&#xff08;选或不选&#…...

【技巧】dify前端源代码修改第一弹-增加tab页

回到目录 【技巧】dify前端源代码修改第一弹-增加tab页 尝试修改dify的前端源代码&#xff0c;在知识库增加一个tab页"HELLO WORLD"&#xff0c;完成后的效果如下 [gif01] 1. 前端代码进入调试模式 参考 【部署】win10的wsl环境下启动dify的web前端服务 启动调试…...