基于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);
整体的函数框架
打开数据文件
创建结果文件
在while循环里
读取一行的数据
处理数据
写入结果文件
最后关闭文件
以上就是整个程序的大致框架,现在来写程序,难点还是数据的处理
#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 后面的是要转换的文件名,可以看到十六进制的数据

可以看到,回车换行的十六进制是 0x0d 和 0x0a ,就是我们常用的 '\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文件编程的一个小实验,用文件IO来读取Excel表格的数据,处理后写入另一个文件,本文只是对文件IO的…...
make 程序规定的 makefile 文件的书写语法(2)
(13)接着开始一个更复杂的例子,课程的素材 2 ,先给出书写 makefile 的框架 : (14) (15) 谢谢...
容器化安装jenkins稳定版长期维护版本LTS
前提已有 docker-compose和docker-ce环境,这里安装稳定的Lts版本即可。 选择稳定版本 这里选择LTS 稳定长期维护的版本 在docker镜像找到LTS稳定版本 部署jenkins服务 创建持久化数据目录 jenkinsdata]# pwd /data/jenkinsdata编写docker-compose文件 jenkins_…...
如何让人工智能训练更快
影响人工智能训练时间的因素 在深度学习训练中,训练时间的计算涉及到多个因素,包括 epoch 数、全局 batch size、微 batch size、计算设备数量等。下面是一个基本的公式来说明这些参数之间的关系(注意,这只是一个基本的说明公式&…...
linux/ubuntu国内镜像安装gitleaks敏感信息扫描工具教程及避坑点
1、背景 利用gitleaks扫描git仓库或者文件 GitHub上有比较详细的教程,但是由于每个人的安装环境不同,坑很多,网上能查到的有效信息也比较少。这里就以我坑很多的环境为例,捋一下步骤。 GitHub - gitleaks/gitleaks: Protect an…...
JavaScript高级程序设计基础(二)
二、语言基础 2.1语法 (简单的语法基础将在文章省略) 2.1.1严格模式 严格模式是一种不同的 JavaScript 解析和执行模型,不规范写法在这种模式下会被处理 只需在脚本开头加上"use strict" 也可以单独指定一个函数在严格模式下执…...
使用Spring Boot开发自习室预定系统
开发一个自习室预定系统涉及到用户管理、自习室管理、预定管理等功能。以下是使用Spring Boot开发自习室预定系统的步骤和关键点: 1. 需求分析 确定系统的基本需求,例如: 用户注册和登录管理员管理自习室信息用户浏览可用自习室用户预定自…...
最近读书总结
1《More Joel on Software》读后感【2024年8月29日】 1.1 本书概要 本书讲解了如何发现优秀的IT人才,并把他们招聘进来;如何对智力密集型的IT企业(软件企业)进行管理,即最好采用情感认同法;对计算机大学生…...
python列表判断是否为空的三种方式
#列表是否为空判断 a[]一: if a:print(not null) else:print(null)二: b len(a) if b 0:print(null) else:print(not null)三: if not a:print(null) else:print(not null)运行结果:...
二十三种模式之原型模式(类比制作陶器更好理解一些)
1. 设计模式的分类 创建型模式(五种):工厂方法模式、单例模式、抽象工厂模式、原型模式、建造者模式。 结构型模式(七种):适配器模式、代理模式、装饰器模式、桥接模式、外观模式、享元模式、组合模式。 行为型模式(十一种):状态模式、模板方…...
9.9日记录
1.常见排序算法的复杂度 1.快速排序 1.1快速排序为什么快 从名称上就能看出,快速排序在效率方面应该具有一定的优势。尽管快速排序的平均时间复杂度与“归并排序”和“堆排序”相同,但通常快速排序的效率更高,主要有以下原因。 出现最差情况…...
鸿蒙交互事件开发04——手势事件
1 概 述 手势事件是移动应用开发中最常见的事件之一,鸿蒙提供了一些方法来绑定手势事件。通过给各个组件绑定不同的手势事件,并设计事件的响应方式,当手势识别成功时,ArkUI框架将通过事件回调通知组件手势识别的结果。 …...
研1日记9
1.理解conv1d和conv2d a. 1和2处理的数据不同,1维数据和图像 b. 例如x输入形状为(32,19,512)时,卷积公式是针对512的,而19应该变换为参数中指定的输出通道。 2.“SE块”(Squeeze-and-Excitation Block)它可以帮助模…...
HAL库学习目录查询表
日期内容2024.09.11基于STM32C8T6的CubeMX: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中,computed 属性是基于它们的依赖进行缓存的响应式属性。只有当相关依赖发生改变时,才会重新求值。这意味着只要computed属性依赖的源数据(如data中的属性)没有发生变化,多次访问computed属性会立即返回之前的…...
python之pyecharts制作可视化数据大屏
文章目录 前言一、安装 Pyecharts二、创建 Pyecharts 图表三、设计大屏布局四、实时数据更新五、部署和展示总结前言 使用 Pyecharts 制作可视化数据大屏是一个复杂但有趣的过程,因为 Pyecharts 本身是一个用于生成 Echarts 图表的 Python 库,而 Echarts 是由百度开发的一个…...
Chrome、Edge、360及Firefox浏览器加载多个ActiveX插件的介绍
allWebPlugin简介 allWebPlugin中间件是一款为用户提供安全、可靠、便捷的浏览器插件服务的中间件产品,致力于将浏览器插件重新应用到所有浏览器。它将现有ActiveX控件直接嵌入浏览器,实现插件加载、界面显示、接口调用、事件回调等。支持Chrome、Firefo…...
裸金属服务器与云服务器的区别有哪些?
随着云计算服务的快速发展,云服务器与裸金属服务器则称为各大企业基础设施的两大核心选择,会运用在不同的场景当中,本文就来介绍一下裸金属服务器与云服务器的区别都有哪些吧! 裸金属服务器相对于云服务器来说有着卓越的性能&…...
普通工程师堆起来的人海战术,作用其实很有限
普通工程师堆起来的人海战术,作用其实很有限。为什么这么说?因为芯片项目需要的是那些不可堆积的优势。什么叫不可堆积?就是你招10个普通工程师,也顶不上一个顶尖架构师的价值。架构设计能力、关键IP的积累、底层算法的创新——这些东西不是靠加班加点就能搞出来的…...
【Java杂项】为什么 b += 1 可以,但 b = b + 1 会报错?类型提升与复合赋值详解
【Java杂项】为什么 b 1 可以,但 b b 1 会报错?复合赋值与类型提升讲清楚前言一、先给结论:它不是简单的文本替换二、先看认知冲突2.1 普通赋值为什么报错2.2 复合赋值为什么能通过三、类型提升到底是什么3.1 常见类型提升结果3.2 为什么小…...
Perplexity+知网联合检索的7类失效场景全图谱:从DOI解析失败到CSSCI标识丢失的终极修复手册
更多请点击: https://intelliparadigm.com 第一章:Perplexity知网联合检索的失效机理总论 当用户尝试将 Perplexity AI 的实时网络推理能力与知网(CNKI)学术资源库进行协同调用时,系统级耦合在协议层、语义层与权限层…...
海底管道电伴热机理及系统建模与控制策略【附程序】
✨ 长期致力于电伴热、集肤效应、Hammerstein模型、参数辨识、约束广义预测控制算法、功率调节、场路耦合法研究工作,擅长数据搜集与处理、建模仿真、程序编写、仿真设计。 ✅ 专业定制毕设、代码 ✅ 如需沟通交流,点击《获取方式》 (1&#…...
别再死记硬背了!用Pointer Network让AI学会‘抄作业’,搞定文本摘要和对话生成
别再死记硬背了!用Pointer Network让AI学会‘抄作业’,搞定文本摘要和对话生成 想象一下,当你面对一篇冗长的技术文档时,最有效的学习方法是什么?不是逐字背诵,而是用荧光笔划出关键概念——这正是Pointer …...
ArcGIS 10.2也能用天地图!手把手教你用WMTS服务和lyr文件搞定低版本兼容
ArcGIS 10.2兼容天地图WMTS服务的工程级解决方案 在GIS项目实施过程中,我们常常会遇到软件版本滞后于服务更新的尴尬局面。天地图作为国内权威的地理信息服务,自2019年起仅支持ArcGIS 10.6及以上版本直接加载,这对仍在使用ArcGIS 10.2/10.3等…...
告别卡顿与花屏:i.MX6ULL驱动OV2640摄像头的分辨率设置与V4L2应用层避坑指南
i.MX6ULL驱动OV2640摄像头的分辨率优化与V4L2实战指南 当你在i.MX6ULL平台上成功驱动了OV2640摄像头后,真正的挑战才刚刚开始。许多开发者会遇到这样的困扰:明明硬件连接正确,驱动也加载了,但图像输出却出现各种异常——画面只有一…...
技术从业者的情绪管理:如何应对工作压力和职业焦虑
一、软件测试从业者的情绪困境:压力源与焦虑画像在敏捷开发与DevOps模式深度普及的今天,软件测试早已不是传统意义上的“事后把关”,而是贯穿需求分析、代码开发、上线运维全流程的质量核心环节。这种角色转变,也让测试从业者面临…...
基于雪崩晶体管设计2ns快速边沿脉冲发生器:原理、实现与调试
1. 项目概述与核心价值在射频、高速数字电路测试,甚至是核物理、激光雷达的前沿实验中,我们常常会遇到一个令人头疼的问题:市面上能买到的标准脉冲信号源,其输出脉冲的上升时间(Rise Time)往往在几十纳秒甚…...
从CNN到ViT:混合网络架构的设计哲学与PyTorch实战
1. 项目概述:为什么我们需要混合网络?在计算机视觉领域待了十几年,我亲眼见证了模型架构的“风水轮流转”。从早期的LeNet、AlexNet,到后来统治多年的ResNet、DenseNet等纯卷积神经网络,再到这两年Transformer架构&…...
