📝前言:
这篇文章我们来讲讲Linux——基础IO主要包括:
- 文件基本概念
- 回顾 C文件的操作
- 介绍系统关于文件的基本操作
🎬个人简介:努力学习ing
📋个人专栏:Linux
🎀CSDN主页 愚润求学
🌄其他专栏:C++学习笔记,C语言入门基础,python入门基础,C++刷题专栏
目录
一,基本概念
1. 概念
- 狭义:
- 文件在磁盘上
- 磁盘是永久性存储物质
- 磁盘是外设,即是输入设备,也是输出设备
- 对文件的操作,其实是对外设的输入和输出,称为 IO
- 广义:
- Linux 下⼀切皆文件
- 文件 == 内容 + 属性
2. 系统角度
- 对⽂件的操作本质是进程对⽂件的操作
- 硬件(如磁盘)的管理者是操作系统
- ⽂件的读写本质不是通过 C 语⾔ / C++ 的库函数来操作的(这些库函数只是为用户提供⽅便),底层是通过文件相关的系统调用接口来实现的
二,C 文件的 IO
1. 打开操作
fopen:
FILE *fopen(const char *pathname, const char *mode);
pathname
:文件路径mode
:打开方式
- 返回:
- 成功:返回文件指针
- 失败:返回
NULL
这个FILE
的类型是一个文件结构体struct file
,通过typedef
来的
2. 写操作
写操作,在文件不存在的时候都会创建文件。
打开文件时的写入模式:
- 清空写
w
:清空文件内容,重新写 - 追加写
a
:在原来文件内容后面追加写
fwrite:
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
- 把
ptr
的数据写到stream
size
:每个数据项的大小,比如写int
,siezeof(int)
(就是4
)nmemb
:数据项的个数
- 把
- 返回:实际成功写入的数据项数量
注意:文件写入的时候不能写入'\0'
,'\0'
是C语言的东西,写入了以后是乱码
示例:
5 // C 语言文件接口回顾
6 int main()
7 {
8 FILE* fp1 = fopen("log1.txt", "w");
9 FILE* fp2 = fopen("log2.txt", "a");
10 if(fp1 == NULL) printf("log1.txt 打开失败\n");
11 if(fp2 == NULL) printf("log2.txt 打开失败\n");
12 char* str1 = (char *)"测试写入\n";
13 fwrite(str1, strlen(str1), 1, fp1);
14 fwrite(str1, strlen(str1), 1, fp2);
15 fclose(fp1);
16 fclose(fp2);
17 return 0;
18 }
当使用相对路径的时候,进程通过自己记录的自己工作路径CWD
信息,知道新建的文件要放在哪里
运行结果:
3. 读操作
读操作,如果文件不存在会报错
fread:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
- 不解释了,和
fwrite
的都一样,不一样的就是stream
是读入的流,ptr
是存储读入数据的地方。 - 在上一次读取结束后文件指针的位置继续读取。
- 不解释了,和
- 返回:实际成功读取的数据项数量
示例:
20 int main()
21 {
22 FILE* fp = fopen("log2.txt", "r");
23 if(fp == NULL) printf("打开文件失败");
24
25
26 char* str1 = (char *)"测试写入\n";
27 char buff[1024];
28 while(1)
29 {
30 // 这里每次读都是覆盖写buff的,但是我们及时打印出来
31 int s = fread(buff, 1, sizeof(str1), fp); // 这里每次读一个char,方便后续设置 '\0'
32 if(s > 0)
33 {
34 buff[s] = 0;
35 printf("%s", buff);
36 }
37 if(feof(fp))
38 break;
39 }
40 return 0;
41 }
运行结果:
4. 默认打开的流
#include <stdio.h>
extern FILE *stdin;
extern FILE *stdout;
extern FILE *stderr;
C默认会打开三个输⼊输出流,分别是标准输入:stdin
, 标准输出:stdout
, 标准错误:stderr
三,系统文件的 IO
头文件:<unistd.h>
1. 位标记传递
利用位图进行标记位传递,假设,现有标记位:ONE : 0001
,TWO:0010
、THREE:0100
- 如果我们单独传入一个
ONE
就相当于传递了最低位的1
。 - 如果我们希望传递第最低位的
1
和次低位的1
,就可以传入ONE | TWO
(通过获的方式)
2 系统调用 open
系统,通过系统调用open
打开文件:
pathname
:文件路径falgs
:选项(约等于C语言里面的打开模式),通过 或|
来实现传递多个选项【这个选项本质是宏实现的标记位】- 常见选项:
O_RDONLY
:只读打开O_WRONLY
: 只写打开O_RDWR
: 读,写打开
- 上面这三个常量,必须指定⼀个且只能指定⼀个。
- 其他选项
O_CREAT
:若文件不存在,则创建它。需要使用mode
选项(传入3个8进制数字),来指明新文件的访问权限。如果新建的时候,不传入,那对应的文件就是乱码【别忘了实际的权限要考虑umask
的影响】O_APPEND
:追加写
- 返回值
- 成功:新打开的文件的文件描述符(系统通过这个来找到需要访问的文件)
- 失败:-1
3 读写的系统调用
write:
- 参数
fd
:文件描述符buf
:指向:要写入的数据,的缓冲区指针count
:要写入的字节数
- 返回
- 成功:实际写入的字节数
- 失败:-1,并设置errno
- 写入类型
- 对于系统而言,没有什么文本写入和二进制写入(这是语言层的概念)
- 你传什么指针,他就写什么,如果你原来数据是一个
int a
,指针传&a
,则它就是按二进制写
read和write
一样,只是这里是读到buf
其余close
、 lseek
接口类似C语言
使用示例
以写入为例:
45 int main()
46 {
47 int fd = open("log.txt", O_WRONLY | O_CREAT | O_APPEND, 0666); // 这个打开的效果就相当于 C 语言库函数的直接 mode 为 a
48 const char* str = (char*)"hello world!\n";
49 write(fd, str, strlen(str)); // 不写入 '\0'
50 char fd_str[20];
51 sprintf(fd_str, "%d\n", fd); // 转换为文本
52 write(fd, fd_str, strlen(fd_str));
53 close(fd);
54 return 0;
55 }
通常如果是read
,则open
就是用带两个参数的
运行结果:
库函数和系统调用
- C语言的库函数
fwrite
和fread
其实都是对底层系统调用write
和read
的封装,在上层为用户提供便利。 - C语言的库函数具有可移植性,但是系统调用没有
- 系统调用,如:Linux 的,用的是Linux这一套的。如果把代码移植到Windows或者其他操作系统就不行了
- C语言,C的
fwrite
和fread
是对系统调用的封装,但是它不只封装一份操作系统的,它会实现多个操作系统的。后续根据自己在哪个操作系统上使用,通过条件编译(裁剪),来调用对应的系统接口
4 文件描述符(重点)
什么是文件描述符?
如上图所展示的 3
就新打开的log.txt
的文件描述符
0, 1, 2
分别对应 stdin
, stdout
, stderr
那系统是如何通过文件描述符来找到要访问的文件的呢?
- 在进程的
task_struct
里面有一个files
指针,指向文件描述表files_struct
- 在文件描述表中,有
fd_array[]
指针数组,数组的下标对应着文件描述符,指向对应的文件 - 而每个文件被描述成一个结构体
struct file
(类似C语言的FILE
),里面存储着文件的信息
有了文件描述符fd
,进程就会在自己的文件描述表里面找对应下标的文件指针,然后就可以访问对应的文件了。
文件描述符的分配原则
在files_struct
数组当中,找到当前没有被使用的最小的⼀个下标,作为新的⽂件描述符。
比如,一开始有0, 1, 2
:
- 直接创建一个新文件,则新文件
fd == 3
- 先
close(1)
,再创建新文件,则fd == 1
注意:这里的关闭不是真关闭,只是“引用计数 - 1”。
- 因为一个文件可以同时被多个进程访问
- 同一个文件也可以被同一个进程的多个下标指针同时指向。比如
stdout
和stderr
其实都是向显示器输出
🌈我的分享也就到此结束啦🌈
要是我的分享也能对你的学习起到帮助,那简直是太酷啦!
若有不足,还请大家多多指正,我们一起学习交流!
📢公主,王子:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!