news 2026/4/16 12:29:14

【Linux 封神之路】文件操作 + 时间编程实战:从缓冲区到时间格式化全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Linux 封神之路】文件操作 + 时间编程实战:从缓冲区到时间格式化全解析

【Linux 封神之路】文件操作 + 时间编程实战:从缓冲区到时间格式化全解析

大家好,我是专注 Linux 技术分享的小杨。上一篇给大家整理了系统监控与性能分析工具,解决了服务器卡慢、程序崩溃的问题。今天接着 Linux 开发核心技能系列,聚焦 “文件操作” 和 “时间编程”—— 这两个是嵌入式 Linux 开发的高频需求,比如日志写入、配置文件读写、时间戳记录等场景都离不开。结合文件操作及时间编程资料,从 “缓冲区 / 非缓冲区文件操作” 到 “时间格式转换”,手把手教你实战用法,附完整代码示例,新手直接套用!

一、先理清:文件操作的两种核心方式

Linux 文件操作分为 “基于缓冲区” 和 “基于非缓冲区” 两种,适用场景不同,核心区别在于是否通过标准库缓冲区优化 IO 效率:

  • 基于缓冲区(fopen/fwrite/fread):标准库封装,自动缓冲数据,减少系统调用次数,适合普通文件读写(如文本文件、配置文件);
  • 基于非缓冲区(open/write/read):直接调用系统调用,无中间缓冲,实时性高,适合设备文件操作(如串口、磁盘)、嵌入式实时场景。

下面分别拆解两种方式的核心函数和实战代码。

二、实战 1:基于缓冲区的文件操作(标准库函数)

基于缓冲区的文件操作通过<stdio.h>头文件的函数实现,用法简单、兼容性好,是开发中的首选。

1. 核心函数详解(按操作流程)

函数功能核心参数 / 返回值
fopen打开 / 创建文件参数 1:文件路径(如"test.txt");参数 2:打开模式("r"读、"w"写、"a"追加、"r+"读写);返回值:文件指针(FILE *),失败返回NULL
fwrite写入数据参数 1:数据缓冲区地址;参数 2:单个数据大小;参数 3:数据个数;参数 4:文件指针;返回值:成功写入的个数
fprintf格式化写入(文本文件)类似printf,多一个文件指针参数(如fprintf(fp, "name:%s\n", "Linux")
fread读取数据参数 1:接收数据的缓冲区;参数 2:单个数据大小;参数 3:读取个数;参数 4:文件指针;返回值:成功读取的个数
fscanf格式化读取(文本文件)类似scanf,多一个文件指针参数(如fscanf(fp, "%d", &num)
fseek移动文件光标参数 1:文件指针;参数 2:偏移量(正值向右、负值向左);参数 3:基准位置(SEEK_SET文件开头、SEEK_CUR当前位置、SEEK_END文件末尾)
fclose关闭文件参数:文件指针;返回值:0 成功,-1 失败(必须关闭,避免资源泄漏)

2. 实战代码:文本文件读写(日志记录场景)

c

运行

#include <stdio.h> #include <string.h> int main() { // 1. 打开文件(不存在则创建,存在则追加写入) FILE *fp = fopen("app.log", "a+"); if (fp == NULL) { perror("fopen failed"); return 1; } // 2. 格式化写入数据(模拟日志:时间+内容) char log_msg[] = "2026-01-28 16:00:00 [INFO] 程序启动成功\n"; fprintf(fp, "%s", log_msg); // 3. 移动光标到文件开头,读取所有日志 fseek(fp, 0, SEEK_SET); char buf[1024]; printf("日志内容:\n"); while (fgets(buf, sizeof(buf), fp) != NULL) { // 逐行读取 printf("%s", buf); } // 4. 关闭文件 fclose(fp); fp = NULL; // 避免野指针 return 0; }

3. 关键注意事项

  • 打开模式选择:"w"会清空文件原有内容,"a"会在文件末尾追加,"r+"支持读写但不会创建文件;
  • 必须检查fopen返回值:文件不存在、权限不足都会导致打开失败;
  • 写完数据后若需立即读取,需用fseek移动光标(否则光标在文件末尾,读取不到数据)。

三、实战 2:基于非缓冲区的文件操作(系统调用)

非缓冲区文件操作通过系统调用实现,无中间缓冲,IO 响应更快,适合嵌入式实时场景(如串口通信、磁盘 IO)。

1. 核心函数详解(按操作流程)

函数功能核心参数 / 返回值
open打开 / 创建文件参数 1:文件路径;参数 2:打开标志(必选:O_RDONLY只读、O_WRONLY只写、O_RDWR读写;可选:O_CREAT创建、O_APPEND追加、O_TRUNC清空);参数 3:文件权限(O_CREAT时必填,如0644=rw-r--r--);返回值:文件描述符(int),失败返回 - 1
write写入数据参数 1:文件描述符(open 返回值);参数 2:数据缓冲区;参数 3:数据长度;返回值:成功写入的字节数,失败返回 - 1
read读取数据参数 1:文件描述符;参数 2:接收缓冲区;参数 3:读取长度;返回值:成功读取的字节数(0 表示文件结束),失败返回 - 1
lseek移动光标参数 1:文件描述符;参数 2:偏移量;参数 3:基准位置(SEEK_SET/SEEK_CUR/SEEK_END);返回值:光标位置的字节数,失败返回 - 1
close关闭文件参数:文件描述符;返回值:0 成功,-1 失败

2. 实战代码:二进制文件读写(数据存储场景)

c

运行

#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> // 定义要存储的结构体(模拟传感器数据) typedef struct { int temp; // 温度 int humidity;// 湿度 long time; // 时间戳 } SensorData; int main() { // 1. 打开文件(创建+读写+清空原有内容,权限0644) int fd = open("sensor.bin", O_RDWR | O_CREAT | O_TRUNC, 0644); if (fd == -1) { perror("open failed"); return 1; } // 2. 准备数据并写入(二进制格式) SensorData data = {25, 60, 1738064000}; ssize_t write_len = write(fd, &data, sizeof(SensorData)); if (write_len != sizeof(SensorData)) { perror("write failed"); close(fd); return 1; } printf("写入二进制数据成功,长度:%ld字节\n", write_len); // 3. 移动光标到文件开头,读取数据 lseek(fd, 0, SEEK_SET); SensorData read_data; ssize_t read_len = read(fd, &read_data, sizeof(SensorData)); if (read_len == -1) { perror("read failed"); close(fd); return 1; } printf("读取数据:温度=%d℃,湿度=%d%%,时间戳=%ld\n", read_data.temp, read_data.humidity, read_data.time); // 4. 关闭文件 close(fd); return 0; }

3. 关键注意事项

  • 文件权限:0644表示所有者可读可写,组用户和其他用户只读(嵌入式开发中常用权限);
  • 文件描述符:open返回的是整数(如 3、4),而非FILE *,需注意与缓冲区操作的区别;
  • 无缓冲特性:write调用后数据直接写入文件(或设备),无需刷新缓冲区,实时性更高。

四、实战 3:时间编程(时间戳 + 格式化转换)

时间编程在日志记录、数据同步、定时任务中必不可少,核心是 “时间戳→时间结构体→格式化字符串” 的转换流程。

1. 核心概念与结构体

  • 时间戳:从 1970 年 1 月 1 日 0 时 0 分 0 秒(UTC)到当前时间的秒数(time_t类型);
  • 时间结构体(struct tm):拆分后的时间格式,包含秒、分、时、日、月、年等字段(注意:tm_mon从 0 开始,tm_year= 实际年份 - 1900)。

2. 核心函数详解(按转换流程)

函数功能核心参数 / 返回值
time获取当前时间戳参数:保存时间戳的地址(可传NULL直接返回);返回值:当前时间戳,失败返回 - 1
localtime时间戳→本地时间结构体参数:时间戳指针;返回值:struct tm *(本地时间,如北京时间)
gmtime时间戳→格林威治时间结构体参数:时间戳指针;返回值:struct tm *(UTC 时间,比北京时间晚 8 小时)
ctime时间戳→默认格式字符串参数:时间戳指针;返回值:字符串指针(如"Wed Jan 28 16:30:00 2026\n"
asctime时间结构体→默认格式字符串参数:struct tm *;返回值:字符串指针(格式同ctime
strftime时间结构体→自定义格式字符串参数 1:结果缓冲区;参数 2:缓冲区大小;参数 3:格式字符串(如"%Y-%m-%d %H:%M:%S");参数 4:时间结构体;返回值:成功转换的字符数

3. 实战代码:时间格式化(日志时间戳场景)

c

运行

#include <stdio.h> #include <time.h> #include <string.h> int main() { // 1. 获取当前时间戳 time_t now = time(NULL); if (now == -1) { perror("time failed"); return 1; } printf("当前时间戳:%ld\n", now); // 2. 时间戳→本地时间结构体 struct tm *local_tm = localtime(&now); if (local_tm == NULL) { perror("localtime failed"); return 1; } // 3. 自定义格式化时间(常用格式:年-月-日 时:分:秒) char time_str[64]; strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", local_tm); printf("自定义格式时间:%s\n", time_str); // 4. 时间戳→默认格式字符串 char *default_time = ctime(&now); printf("默认格式时间:%s", default_time); // 5. 时间结构体→默认格式字符串 char *asctime_str = asctime(local_tm); printf("asctime格式时间:%s", asctime_str); return 0; }

4. 常用时间格式符(strftime核心)

格式符含义示例
%Y4 位年份2026
%m2 位月份(01-12)01
%d2 位日期(01-31)28
%H24 小时制小时(00-23)16
%M分钟(00-59)30
%S秒(00-59)45
%w星期(0-6,0 为周日)3
%j一年中的第几天(001-366)028

五、综合实战:文件操作 + 时间编程(日志系统)

结合前面的知识点,实现一个带时间戳的日志系统,自动记录程序运行状态:

c

运行

#include <stdio.h> #include <time.h> #include <string.h> // 日志写入函数(带时间戳) void write_log(const char *level, const char *msg) { // 1. 打开日志文件(追加模式) FILE *fp = fopen("system.log", "a"); if (fp == NULL) { perror("fopen log failed"); return; } // 2. 获取当前时间并格式化 time_t now = time(NULL); struct tm *local_tm = localtime(&now); char time_str[64]; strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", local_tm); // 3. 写入日志(格式:时间 级别 消息) fprintf(fp, "[%s] [%s] %s\n", time_str, level, msg); // 4. 关闭文件 fclose(fp); fp = NULL; } int main() { write_log("INFO", "程序启动"); write_log("INFO", "开始执行数据采集"); write_log("WARNING", "传感器数据波动较大"); write_log("INFO", "程序执行完成"); printf("日志写入成功,查看system.log文件\n"); return 0; }

运行后查看system.log文件,输出如下:

plaintext

[2026-01-28 17:00:00] [INFO] 程序启动 [2026-01-28 17:00:01] [INFO] 开始执行数据采集 [2026-01-28 17:00:05] [WARNING] 传感器数据波动较大 [2026-01-28 17:00:10] [INFO] 程序执行完成

六、避坑指南:常见错误解决

  1. 文件操作失败(权限不足)

    • 原因:创建文件时未指定权限(openO_CREAT但未传mode参数),或目录无写权限;
    • 解决:open函数添加权限参数(如0644),或用sudo运行程序(仅测试场景)。
  2. 时间格式化出现乱码

    • 原因:strftime的缓冲区大小不足,或格式符错误;
    • 解决:增大缓冲区(如char time_str[64]),核对格式符(如%Y而非%y)。
  3. 非缓冲区操作读取不到数据

    • 原因:read后未判断返回值,或光标位置错误;
    • 解决:用lseek移动光标到正确位置,检查read返回值(0 表示文件结束,-1 表示失败)。

七、总结:核心技能与应用场景

  1. 文件操作:
    • 普通文本 / 配置文件:用缓冲区操作(fopen/fprintf/fscanf),效率更高;
    • 设备文件 / 实时场景:用非缓冲区操作(open/write/read),实时性更强;
  2. 时间编程:
    • 日志记录:用strftime自定义时间格式,搭配文件操作实现带时间戳日志;
    • 数据同步:用time获取时间戳,实现跨设备时间同步;
  3. 嵌入式适配:
    • 权限控制:嵌入式设备中文件权限需严格配置(如0644),避免权限过高;
    • 资源释放:文件操作后必须关闭(fclose/close),避免资源泄漏。

掌握文件操作和时间编程,能应对嵌入式开发中 80% 的 IO 场景(日志、配置、数据存储)。下一篇博客,我会给大家整理 “Linux 多线程编程”,解决并发执行、资源同步等问题,敬请关注!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 13:05:36

Java springboot基于微信小程序的毕业生就业管理系统学生招聘(源码+文档+运行视频+讲解视频)

文章目录 系列文章目录目的前言一、详细视频演示二、项目部分实现截图三、技术栈 后端框架springboot前端框架vue持久层框架MyBaitsPlus微信小程序介绍系统测试 四、代码参考 源码获取 目的 基于微信小程序的毕业生就业管理系统&#xff0c;采用Spring Boot框架构建后端服务&…

作者头像 李华
网站建设 2026/4/16 10:59:57

不会后端也能做后台?XinServer 教程来了

不会后端也能做后台&#xff1f;XinServer 教程来了 兄弟们&#xff0c;不知道你们有没有遇到过这种情况&#xff1a;产品经理或者老板突然跑过来&#xff0c;说“咱们这个App/小程序/管理后台&#xff0c;需要一个用户管理功能&#xff0c;再加个数据统计&#xff0c;最好下周…

作者头像 李华
网站建设 2026/4/16 15:26:03

【Matlab】MATLAB矩阵纵向拼接详解:从基础语法到批量行数据合并

MATLAB矩阵纵向拼接详解:从基础语法到批量行数据合并 在MATLAB矩阵操作体系中,纵向拼接(也称为垂直拼接)是与横向拼接互补的核心数据整合手段,其核心是将多个矩阵按行方向合并,实现行数据的批量补充与整合。基础语法[A;B]是纵向拼接的典型实现方式,批量拼接则能高效处理…

作者头像 李华
网站建设 2026/4/16 13:27:48

约 6 折官方价!Veo 视频生成 API 欢迎对接

Veo 是 Google 最近出的一个非常强大的模型&#xff0c;很多人都用它来生成各种各样的视频。但是官方的价格还是很贵的&#xff0c;这里介绍一款稳定的 Veo API&#xff0c;稳定性高&#xff0c;帮你节省成本的同时助力您的创作&#xff01; 本文接下来将介绍来自 Ace Data Cl…

作者头像 李华
网站建设 2026/4/13 16:02:33

ssm宠物医院挂号系统r0f38(程序+源码+数据库+调试部署+开发环境)

本系统&#xff08;程序源码数据库调试部署开发环境&#xff09;带论文文档1万字以上&#xff0c;文末可获取&#xff0c;系统界面在最后面。 系统程序文件列表 开题报告内容 一、研究背景与意义 随着宠物数量的增加&#xff0c;宠物健康问题日益受到重视&#xff0c;宠物医…

作者头像 李华
网站建设 2026/4/16 13:05:39

ssm超市管理系统1q934--(程序+源码+数据库+调试部署+开发环境)

本系统&#xff08;程序源码数据库调试部署开发环境&#xff09;带论文文档1万字以上&#xff0c;文末可获取&#xff0c;系统界面在最后面。 系统程序文件列表 开题报告内容 题目&#xff1a;超市管理系统的设计与实现 一、研究背景 随着零售业的快速发展&#xff0c;超市…

作者头像 李华