Linux-基础IO
🌎Linux基础IO
文章目录:
Linux基础IO
C语言中IO交互
常用C接口
fopen
fputs
fwrite
fgets
当前路径
三个文件流
系统文件IO
open函数
参数含义
close函数
write函数
参数含义
文件描述符fd
认识文件描述符
重定向
输出重定向
输入重定向
追加重定向
重定向接口
缓冲区
简单认识缓冲区
技术角度认识缓冲区
FILE结构体
编码模拟
总结
前言:
在刚开始学习Linux的时候,我们记住了Linux下一切皆文件,我们通过这篇文章来深入了解Linux下文件的构成及应用。
🚀C语言中IO交互
✈️ 常用C接口
🚩 fopen
fopen:打开一个文件。
代码示例:
#include
int main()
{
FILE* fp = fopen("./log.txt", "w");//打开一个文件,如果没有则创建一个文件
if(fp == NULL)
{
perror("fopen");
return 1;
}
//文件操作介于打开和关闭之间
fclose(fp);//关闭文件
return 0;
}
注意:
当以 ‘w’ 方式打开文件时:该文件会被清空。
当以 ‘a’ 方式打开文件时:正常打开该文件,如果有写入操作则是追加写入。
当以 ‘r’ 方式打开文件时:仅读取文件。
🚩 fputs
fputs:向文件流中写入一个字符串
代码示例:
#include
int main()
{
FILE* fp = fopen("./log.txt", "w");
if(fp == NULL)
{
perror("fopen");
return 1;
}
const char* str = "this is file operate
";
fputs(str, fp);
fclose(fp);
return 0;
}
🚩 fwrite
fwrite:向二进制文件写入数据。
代码示例:
#include
#include
#define FILENAME "log.txt"
int main()
{
FILE* fp = fopen("./log.txt", "w");
if(fp == NULL)
{
perror("fopen");
return 1;
}
const char* msg = "this is file operate
";
int cnt = 5;
while(cnt)
{
fwrite(msg, strlen(msg), 1, fp);
printf("write %d block
", n);
cnt--;
}
fclose(fp);
return 0;
}
第一个参数:
写入数据的对象。
第二个参数:
基本单位的大小。
第三个参数:
表示写入多少个基本单位。
第四个参数:
表示文件流。
返回值:
表示写入的基本单位的个数,也就是第三个参数。
🚩 fgets
fgets:读取一个字符串。
代码示例:
#include
#include
#include
#include
int main()
{
FILE* fp = fopen("./log.txt", "r");//r方式打开
if(fp == NULL)
{
perror("fopen");
return 1;
}
char buffer[64];
while(1)
{
char* r = fgets(buffer, sizeof(buffer), fp);
if(!r) break;
printf("%s
", buffer);
}
fclose(fp);
return 0;
}
这里我只列举了部分常用C语言IO接口,如果有遗忘,请自行复习。
✈️当前路径
当我们在程序中创建一个文件时,例如使用 fopen函数以 ‘w’ 方式打开文件,文件不存在时则创建文件,但是为什么文件创建位置是在当前路径下呢?
其实是通过该进程的一项属性数据来判断所处路径的,我们可以查询该进程pid,在proc目录下进行查看该进程:
cwd表示该进程当前所处工作目录,exe表示可执行程序所处路径。
注意: 当前路径不是指可执行程序所处路径,而是指该程序运行为进程时所处路径。
✈️三个文件流
刚开始接触Linux的时候,我们都知道有句话叫做:Linux下一切皆文件,那么键盘、显示器、网卡、声卡等等这些对于Linux来说都是文件!
我们使用Linux都知道,想要对一个文件进行操作,我们必须要打开一个文件,这是必须的。但是为什么 显示器文件、键盘文件 这些文件我们并不需要直接打开就可以直接使用呢?
文件在打开的前提一定是基于进程的,而进程在运行的过程中会打开默认的三个流,即标准输入流,标准输出流、标准错误流。而对应C语言中就是 stdin、stdout、stderr
标准输入流对应的设备是键盘、标准输出与标准错误流对应的设备是显示器。
当我们使用C语言运行一个程序的时候,操作系统会默认将这三个流给打开,于是,我们使用printf、scanf、gets、puts等接口时可以直接使用。
也就是说我们的输入输出是因为stdin和stdout流是默认打开的状态,我们可以根据stdin、stdout来直接对屏幕进行输出:
#include
int main()
{
fprintf(stdout, "you can see me
");//对标准输出流进行写入
fprintf(stdout, "yes I'can
");//对标准输出流进行写入
return 0;
}
对标准输出流进行写入,其实就是将数据打印到显示器上!
注意:并不是只有C语言有此特性,其他语言例如C++的cout、cin也具有标准流。这种特性并不是有语言层面提供的,而是由操作系统提供的。
🚀系统文件IO
除了使用C语言或者其他语言的IO交互,我们也可以采用调用系统接口来进行文件访问,而系统调用时更接近于底层的,其他语言都是对系统的系统调用进行封装的。
✈️open函数
open函数是fopen函数的底层,其为Linux的系统调用,函数原型为:
int open(const char *pathname, int flags, mode_t mode);
参数含义
-
pathname:表示 需要传入的文件路径,当只有文件名的时候,表示子在当前目录打开或创建该文件。
-
flags:表示打开文件的方式。通常打开文件的常用方式分为以下几种:
flags选项 | 含义 |
---|---|
O_RDONLY | 以只读的方式打开文件 |
O_WRONLY | 以只写的方式打开文件 |
O_APPEND | 以追加的方式打开文件 |
O_CREAT | 文件不存在时,则创建文件 |
O_RDWR | 以读写的方式打开文件 |
O_TRUNC | 清空文件 |
- mode:表示创建文件的默认方式。不需要创建文件时,这个参数不必传参。
为了能理解第二个参数flags ,我们通过以下代码来观察:
#include
#define O_LISTEN 1// 0001
#define O_TALK 2 // 0010
#define O_READ 4 // 0100
#define O_WRITE 8 // 1000
void Listen()
{
printf("linten English dialog
");
}
void Talk()
{
printf("talk about English
");
}
void Read()
{
printf("read English newspaper
");
}
void Write()
{
printf("write English article
");
}
void operate(int flags)
{
//根据二进制位来判断调用函数接口类型
if(flags & O_LISTEN)
Listen();
if(flags & O_TALK)
Talk();
if(flags & O_READ)
Read();
if(flags & O_WRITE)
Write();
}
int main()
{
operate(O_LISTEN);
printf("
");
operate(O_TALK | O_READ);//按位或运算调用
printf("
");
operate(O_LISTEN | O_TALK | O_READ | O_WRITE);
return 0;
}
我们可以 使用或运算 来做出 不同的行为,同样,open接口的flags参数也是如此使用方式,例如,我们以 使用open模拟fopen函数的 ‘w’ 行为:
#include
#include
#include
#include
int main()
{
int fd = open("log.txt", O_WRONLY|O_CREAT, 0666);//文件默认权限设置为666
if(fd == -1)
{
perror("open");
}
return 0;
}
我们确实模仿出了fopen函数的功能,仔细看文件权限,与我们想要的并不同,最后三项应该是 rw- 才对,这是因为存在叫做 权限掩码(umask) 的东西,其通常默认为0002,与mode的关系是 umask & mode,所以我们在设置权限之前,需要把umask设置为0:
#include
#include
#include
#include
int main()
{
umask(0);
int fd = open("log.txt", O_WRONLY|O_CREAT, 0666);//文件默认权限设置为666
if(fd == -1)
{
perror("open");
}
return 0;
}
✈️close函数
int close(int fd);
close函数属于Linux下的系统调用,其功能是 关闭一个文件描述符,参数是 有待关闭的文件描述符。
✈️write函数
函数定义:
ssize_t write(int fd, const void* buf, size_t count);
🚩 参数含义
- fd:需要传入的文件描述符。
- buf:需要写入的字符串的起始位置。
- count:需要写入字符串的长度。
其中第三个参数需要注意,传入的字符串长度是不算