嵌入式学习(day25)文件IO:open read/write close
文件IO:系统调用 Linux内核专门为应用层提供的文件操作方法
1、
#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);
功能:打开文件并获得一个文件描述符。
参数:
pathname: 要打开的文件的文件名
flags: 打开方式
O_RDONLY: 只读方式
O_WRONLY: 只写方式
O_RDWR: 可读可写
O_CREAT: 创建文件
O_TRUNC: 清空文件
O_APPEND: 追加写
标准IO: 文件IO:
"r" O_RDONLY
"r+" O_RDWR
"w" O_WRONLY | O_CREAT | O_TRUNC, 0664
"w+" O_RDWR | O_CREAT | O_TRUNC, 0664
"a" O_WRONLY | O_APPEND | O_CREAT, 0664
"a+" O_RDWR | O_APPEND | O_CREAT, 0664
mode: 文件读写执行操作权限(当flag中有 O_CREAT 标志时,必须要增加 mode 操作权限)
rw-rw-rwx
111111111 ----> 0777
rw-rw-r--
110110100 ----> 0664
返回值:
成功:返回文件描述符。失败:-1
文件描述符:操作系统中已打开文件的标识符。
小的、非负的整形数据
范围:0-1023(总共 1024 个)
分配原则:最小未被使用原则
文件描述符泄露:已打开的文件,使用完时,未及时关闭。
操作系统已经打开的三个文件占用了 0、1、2 这三个文件描述符:
标准 IO: 文件 IO
FILE * int
stdin ----> 标准输入设备 ----> 0
stdout ----> 标准输出设备 ----> 1
stderr ----> 标准出错设备 ----> 2
2、ssize_t write(int fd, const void *buf, size_t count);
功能:向文件中写入数据
参数:
fd: 文件描述符
buf: 要写入的数据的首地址
count: 要写入的字节数
返回值:
成功:实际写入的字节数
失败:-1
3、ssize_t read(int fd, void *buf, size_t count);
功能:从文件中读取数据
参数:
fd: 文件描述符
buf: 存储数据的空间首地址
count: 希望读取的字节数
返回值:
成功:实际读到的字节数
失败:-1
读到文件末尾:0
4、练习:使用文件IO分别实现cat功能和文件拷贝
//实现cat功能
#include <stdio.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc,const char *argv[])
{
int fd =open(argv[1],O_RDONLY);
if(-1 == fd)
{
printf("open error\n");
return -1;
}
char buff[1024] = {0};
while(1)
{
ssize_t cnt = read(fd,buff,sizeof(buff));
if(0 == cnt)
{
break;
}
else if(-1 == cnt)
{
printf("read error\n");
break;
}
write(1,buff,cnt);
}
close(fd);
return 0;
}
//文件的拷贝功能
#include <stdio.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc,const char *argv[])
{
int fread =open(argv[1],O_RDONLY);
int fwrite = open(argv[2],O_WRONLY | O_CREAT | O_TRUNC,0664);
if(-1 == fread || 1 ==fwrite)
{
printf("open error\n");
return -1;
}
char buff[1024] = {0};
while(1)
{
ssize_t cnt = read(fread,buff,sizeof(buff));
if(cnt <= 0)
{
break;
}
write(fwrite,buff,cnt);
}
close(fread);
close(fwrite);
return 0;
}
5、文件定位函数:lseek:
off_t lseek(int fd, off_t offset, int whence);
功能:文件读写位置定位
参数:
fd: 文件描述符
offset: 偏移量(字节)
whence: 要偏移的相对位置
SEEK_SET: 文件开头位置
SEEK_CUR: 文件当前读写位置
SEEK_END: 文件末尾
返回值:
成功:返回当前读写位置到文件开头的偏移量
失败:-1
求文件大小:
off_t len = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET); // 文件读写位置复位。
6、标准IO、文件IO区别:
标准IO:
1. 属于C库函数,移植性强
2. 标准IO是系统调用的一次封装,增加了缓冲区,目的是提高数据读写的效率
3. 标准IO主要用在对普通文件的操作
文件IO:
1. 属于系统调用,只能用于Linux操作系统,移植性弱
2. 文件IO无缓冲区
3. 文件IO主要应用在对硬件的操作的,也可以操作普通文件

7、缓冲区:
(1) 行缓冲 1k(1024字节) ----> 人家交互界面、终端
缓冲区被刷新的方法:
1. 程序结束,自动刷新缓冲区
2. 遇到\n刷新
3. fflush()强制刷新
4. 缓冲区满刷新
(2) 全缓冲 4k(4096字节) ----> 文件缓冲区
缓冲区被刷新的方法:
1. 程序结束,自动刷新缓冲区
2. fflush()强制刷新
3. 文件关闭刷新
4. 缓冲区满刷新
(3) 无缓冲 0k --------> 出错信息对应的设备
stderr----> 无缓冲
练习:日志模块的编写:
要求:
1. 以文件方式保存日志信息
要求文件名字如下:20250812.log
2. 日志文件保存格式如下:
[2025-08-12 17:09:23][日志等级] 日志信息!
[2025-08-12 17:09:23][ERROR] 打开文件失败!
[2025-08-12 17:09:23][WARNING] xxx模块重新启动!
[2025-08-12 17:09:23][INFO] 显示设备初始化成功!
日志等级:
2 ---> ERROR: 表示严重错误
1 ---> WARNING: 对系统不会产生严重问题的告警信息
0 ---> INFO: 调试信息
3. 封装以下函数完成:
int init_log();
功能:在系统运行之初,创建并打开日志文件
int write_log(int level, char *info);
功能:系统运行过程中,需要记录日志信息时,进行日志数据写入
void uninit_log();
功能: 系统运行结束之前,关闭日志
4. 测试:
init_log();
while (1)
{
write_log(xxx, xxxxxx);
sleep(1);
}
uninit_log();
时间相关的函数接口:
1. time();
2. localtime();
3. ctime();
功能: 将time_t类型的秒数转换成字符串时间
int fprintf(FILE *stream, const char *format, ...);
功能: 将格式化后的字符串写入文件流指针所对应的文件中
sprintf();
//log.c 文件:
#include "log.h"
#include <stdio.h>
#include <time.h>
Log_t log_g;
int init_log()
{
char filename[512] = {0};
time_t sec;
sec = time(NULL);
struct tm *pt = localtime(&sec);
log_g.creat_tim = *pt;
//20250813.log
sprintf(filename, "./LOG/%04d%02d%02d_%02d.log", pt->tm_year+1900, pt->tm_mon+1, pt->tm_mday,
pt->tm_min);
log_g.fp = fopen(filename, "a");
if (NULL == log_g.fp)
{
printf("fopen log error\n");
return -1;
}
return 0;
}
int write_log(Log_lev_t lev, char *info)
{
char *lev_str[] = {"INFO", "WARNING", "ERROR"};
time_t sec;
sec = time(NULL);
struct tm *pt = localtime(&sec);
//if (pt->tm_mday != log_g.creat_tim.tm_mday)
if (pt->tm_min != log_g.creat_tim.tm_min)
{
uninit_log();
init_log();
}
fprintf(log_g.fp, "[%04d-%02d-%02d %02d:%02d:%02d][%s] %s\n",
pt->tm_year+1900, pt->tm_mon+1, pt->tm_mday,
pt->tm_hour, pt->tm_min, pt->tm_sec,
lev_str[lev], info);
fflush(log_g.fp);
return 0;
}
void uninit_log()
{
if (log_g.fp != NULL)
{
fclose(log_g.fp);
}
}
//log.h文件
#ifndef __LOG_H__
#define __LOG_H__
#include <stdio.h>
#include <time.h>
typedef enum
{
LOG_INFO,
LOG_WARNING,
LOG_ERROR,
}Log_lev_t;
typedef struct log
{
FILE *fp;
struct tm creat_tim;
}Log_t;
extern int init_log();
extern int write_log(Log_lev_t lev, char *info);
extern void uninit_log();
#endif
//main.c
#include "log.h"
#include <unistd.h>
int main(int argc, const char *argv[])
{
init_log();
while (1)
{
write_log(LOG_INFO, "显示设备初始化成功!");
sleep(1);
write_log(LOG_WARNING, "xxx文件打开出错!");
sleep(1);
write_log(LOG_ERROR, "网络模块初始化失败!");
sleep(1);
}
uninit_log();
return 0;
}
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐


所有评论(0)