文件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;
}

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐