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

Linux操作系统之文件IO

初始文件

文件的宏观理解:文件是在硬盘上存储的,对文件的所有操作,都是对外设的输入输出,简称IO

即使磁盘上有空文件,但是他依然占用我们的磁盘空间,因为文件=内容+属性(元数据),这里只是说的内容的大小和占用空间,而文件的属性也是占用空间的,所以一个空文件依旧占用磁盘空间,所以我们所学的文件操作,本质上不是对属性的操作就是对内容的操作

代码变成进程的过程:文件操作代码->.exe文件->加载到内存中->进程

对文件的操作,本质都是进程对文件的操作,C语言提供的库函数是在用户层,不能直接访问硬件,库函数是去调用系统调用接口去访问硬件的

复习C语言文件IO操作

1、先见一下,如何使用C语言系统调用去创建文件

#include <stdio.h> #include <string.h> int main() { FILE* fp = fopen("log.txt", "w"); // 打开log.txt文件,不存在就创建 if (fp == NULL) { perror("fopen"); // perror函数会自动根据错误码报告错误 return 1; } fclose(fp); return 0; }

可以看到输入上面的代码,“w”就是读写,要是文件不存在就创建一个

2、如何在文件里面写数据

#include <stdio.h> #include <string.h> int main() { FILE* fp = fopen("log.txt", "a"); if (fp == NULL) { perror("fopen"); // perror函数会自动根据错误码报告错误 return 1; } int cnt=5; while(cnt) { fprintf(fp,"%s:%d\n","hellow,frank",cnt--); } fclose(fp); return 0; }

可以看到“a”就是追加,在里面编写数据,可以看到我在里面写了5个数据,最后五个

3、如何去读取文件的数据呢?

#include <stdio.h> #include <string.h> int main() { FILE* fp = fopen("log.txt", "r"); if (fp == NULL) { perror("fopen"); // perror函数会自动根据错误码报告错误 return 1; } // // int cnt=5; // while(cnt) // { // fprintf(fp,"%s:%d\n","hellow,frank",cnt--); // } char a[64]; while(fgets(a,sizeof(a)-1,fp)!=NULL) { a[strlen(a)-1]=0; puts(a); } fclose(fp); return 0; }

r就是读写,要是不存在了话就出错

系统调用的IO操作

1、open打开文件

int open(const char *pathname, int flags);

int open(const char *pathname, int flags, mode_t mode);

O_RDONLY: 只读打开

O_WRONLY: 只写打开

O_RDWR : 读,写打开

(以上三个常量,必须指定一个且只能指定一个)

O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限

O_APPEND: 追加写

O_TRUNC:如果文件已存在且成功打开,则将文件长度截断至0(清空文件再写入,如果不带 O_TRUNC选项,文件将被打开但不会自动被截断。这意味着,如果文件已经存在,它的内容不会被清空,文件指针会放在文件的开始位置,接下来的写操作会从文件的开始处覆盖现有数据。)

mode:权限位,要考虑umask权限掩码的存在

返回值:打开成功返回文件描述符,打开失败返回-1

2、close关闭文件

int close(int fd);

fd:文件描述符

返回值:关闭成功返回0,关闭失败返回-1并可以设置全局变量errno指示错误原因

3、write写入文件

ssize_t write(int fd, const void *buf, size_t count);

fd:文件描述符

buf:要写入数据的缓冲区指针

count:写入数据的字节数

返回值:ssize_t是有符号整型数,写入成功返回写入字节数,写入失败返回-1并可以设置全局变量errno指示错误原因

4、read读取文件

ssize_t read(int fd, void *buf, size_t count);

fd:文件描述符

buf:指向缓冲区的指针,用于存储从文件中读取的数据

count:要读取的最大字节数

返回值:读取成功返回读取到的字节数,若读取到文件末尾返回0,读取失败返回-1并可以设置全局变量errno指示错误原因

代码演示:

#include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <string.h> int main() { int fd = open("log.txt", O_WRONLY | O_CREAT, 0666); // 只写方式打开log.txt文件,不存在就创建,并设置文件权限为0666 if (fd < -1) { // 打开文件失败 perror("open"); return 1; } const char* a = "hello frank\n"; write(fd, a, strlen(a)); // 写入文件 close(fd); // 关闭文件 return 0; }
#include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <string.h> int main() { int fd = open("log.txt", O_RDONLY); // 只读方式打开文件 if (fd 《= -1) { // 打开失败 perror("open"); return 1; } char a[1024]; // 用于存储从文件中读取数据的缓冲区 ssize_t read_bytes = read(fd, a, sizeof(a) - 1); if (read_bytes == -1) { // 读取失败 perror("read"); close(fd); return 1; } a[read_bytes] = '\0'; // 确保读取的数据以空字符结尾 printf("Read from file: %s\n", a); close(fd); return 0; }

文件描述符

当进程打开文件时,操作系统要在内存中创建内核数据结构file来描述被打开的文件,该数据结构中有文件属性,文件内核级缓冲区等

描述进程的内核数据结构task_struct中都有一个指向文件描述符表的指针files,该指针指向一张文件描述符表files_struct,文件描述符表中最重要的部分就是一个指针数组,每一个元素就是一个被打开文件的指针file*,而文件描述符fd就是文件在指针数组中的位置下标。

Linux系统中,每个进程都会默认打开三个文件描述符为0、1、2的文件,分别为标准输入、标准输出、标准错误,对应的物理设备一般为键盘、显示器、显示器

C语言中的文件IO对比系统调用文件IO

C语言中打开文件使用fopen函数,并用FILE*类型接收其返回值。

FILE*是一个指向FILE结构体的指针,该结构体中封装了文件IO的相关的信息,例如文件描述符fd就被封装在其中。因此可以使用FILE*访问文件描述符(C语言中文件描述符叫做_fileno)

#include <stdio.h> int main() { FILE* fp = fopen("log.txt", "w"); // 以w方式打开文件 if (fp == NULL) { perror("fopen"); return 1; } printf("fd:%d\n", fp->_fileno); // 查看文件描述符 fwrite("hello", 1, 5, fp); // 写入文件 fclose(fp); // 关闭文件 return 0; }

C语言程序默认也会打开标准输入stdin、标准输出stdout和标准错误stderr,通过代码查看其对应的文件描述符,发现恰好也是0、1、2

#include <stdio.h> int main() { printf("stdin->fd:%d\n", stdin->_fileno); printf("stdout->fd:%d\n", stdout->_fileno); printf("stderr->fd:%d\n", stderr->_fileno); return 0; }

总结,不难发现其实C语言中的文件IO操作斗士队系统调用文件IO操作的封装

http://www.gsyq.cn/news/149166.html

相关文章:

  • 现代密码学【4】之计算安全性安全规约证明对称加密的窃听不可区分实验
  • 1 小时速通!手把手教你从零搭建 Astro 博客并上线
  • C#基础语言练习--排序列表、File文件读写操作、FileStream文件流、二进制数据读写操作
  • 别再盲目手写论文了!6款AI写论文工具,真实参考文献,AIGC率低至11%
  • 鸿蒙应用开发之用户首选项(Preferences)使用
  • 推出新型面向 AI 加速器的高性能编程框架——PyPTO
  • 2025 年公众号排版软件怎么选?6 款主流编辑器真实横评
  • 18.0环实现线程和进程的监控(ObRegisterCallbacks函数)-Windows驱动
  • 有关LangChain
  • 用NLMS实现对语音的回声的消除,共4个文件,语音原声,语音回声,NLMS的实现
  • Flutter---轮播图
  • 千匠大宗电商系统:赋能煤炭能源行业产业升级
  • 2-[(1-戊炔酰基)氨基]-2-脱氧-D-葡萄糖 — 代谢调控研究的新型探针试剂 1635433-54-3
  • 51、卷积层(计算规则)
  • 【协议】vlan
  • 机械臂轨迹规划算法,基于改进灰狼加353多项式的机械臂轨迹规划时间最优算法。 改进灰狼改进的灰...
  • 基于改进鹈鹕算法(IPOA)优化BP神经网络的智能数据回归预测模型——IPOA-BP模型及其评...
  • 【技术报告解读】DeepSeek-OCR: Contexts Optical Compression
  • Java毕设选题推荐:基于java零售与仓储管理系统的设计与实现基于Java的仓库管理系统(进销存)完整设计与实战【附源码、mysql、文档、调试+代码讲解+全bao等】
  • 内容负责人必读:构建企业GEO优化体系的几大关键
  • 烦心之烦心
  • 长忆——我的OI回忆录
  • 鸿蒙应用开发之通过Scroll、nestedScroll实现京东秒杀嵌套滚动效果
  • VMware Horizon 与 Docker 冲突排错记录
  • Iridescent:Day34
  • 2025最新!9个AI论文平台测评:继续教育写论文痛点全解析
  • 8个降AI率工具推荐!继续教育学生必看
  • 路由策略和策略路由区别是什么
  • 深入剖析WordPress插件漏洞:未授权攻击的成功之道
  • GIF压缩策略优化:从激进到智能的演进之路