1、文件基础知识
2、文件接口
3、文件描述符
4、重定向原理
5、如何理解一切皆文件
1、文件基础知识
1、文件=文件内容 + 属性(也是数据)。
2、文件的所有操作,无外乎:对内容、对属性。
3、是进程在访问文件,文件在磁盘(硬件)放着,是操作系统提供的文件类调用接口能让用户写入,且操作系统层面的接口只有一套。
4、在linux中,一切皆文件,包括键盘、显示器等。
2、文件接口
C文件接口
写文件
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp = fopen("myfile", "w");
if(!fp){
printf("fopen error!\n");
}
const char *msg = "hello log.txt!\n";
int count = 5;
while(count--){
fwrite(msg, strlen(msg), 1, fp);
}
fclose(fp);
return 0;
}
读文件
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp = fopen("myfile", "r");
if(!fp){
printf("fopen error!\n");
}
char buf[1024];
const char *msg = "hello log.txt!\n";
while(1){
//注意返回值和参数,此处有坑,仔细查看man手册关于该函数的说明
ssize_t s = fread(buf, 1, strlen(msg), fp);
if(s > 0){
buf[s] = 0;
printf("%s", buf);
}
if(feof(fp)){
break;
}
}
fclose(fp);
return 0;
}
输出信息到显示器的方法:
#include <stdio.h>#include <string.h>int main(){const char *msg = "hello fwrite\n";fwrite(msg, strlen(msg), 1, stdout);printf("hello printf\n");fprintf(stdout, "hello fprintf\n");return 0;}![]()
C语言会默认打开三个输入输出流,分别是stdin,stdout,stderr。
系统文件I/O
用系统接口来进行文件访问,实现和上面一模一样的代码:
写文件:
读文件:
接口介绍:open
#include <sys/types.h>
#include <sys/stat.h>
#include <fctnl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
pathname:要求打开或创建的目标文件
flags:打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成flags。
参数:
O_RDONLY :只读打开
O_WRONLY:只写打开
O_RDWR :读、写打开
这三个常量,必须指定一个且只能指定一个
O_CREAT :若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
O_APPEND:追加写
返回值:
成功:新打开的文件描述符
失败:-1
3、文件描述符
文件描述符就是一个小整数,Linux进程默认情况下会有三个缺省打开的文件描述符,分别是标准输入0,标准输出1,标准错误2。
0,1,2对应的物理设备一般是:键盘,显示器,显示器。
打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file结构体,表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进程和文件关联起来。每个进程都有一个指针*files,指向一张表files_struct,该表最重要的部分就是包含一个指针数组,每个元素都是一个指向打开文件的指针。所以,本质上,文件描述符就是该数组的下标。所以,只要有文件描述符,就可以找到对应的文件。
文件描述符的分配规则
如果关闭0或者2
fd便变成了0或2
fd分配规则:在files_struct数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。
4、重定向原理
上面的例子没有举close(1)的例子,因为会发生输出重定向,先看现象:
运行程序后发现没有东西被输出到显示器上,因为内容被输出到了文件中
close(1)便实现了输出从显示器到文件的重定向
输出重定向原理:
当close(1)后,凡是往1号文件描述写的内容,都写到了log.txt中,而不是标准输出即显示屏中,但是在操作系统层面上,stdout对应的是1号文件,所以当调用如printf,fprint等输出函数时,它们的内容也会输出到1号文件所指向的log.txt中,这就是输出重定向的原理。
使用dup2系统调用实现重定向
int dup2 (int oldfd, int newfd);
这个函数的逻辑是将oldfd指向的地址拷贝给newfd,就比如上面的代码将原本3号文件指向的log.txt的地址拷贝给了1号文件,从而断开了1号文件与标准输出的连接来实现了输出重定向。
5、如何理解一切皆文件
linux是用C语言编写的,那么如何用C语言实现面向对象呢?
在C++中,类是实现面向对象的方法,所以用C语言去模拟类便可以解决面向对象,类中包含1、成员属性,2、成员方法。C语言中结构体中的数据可以看作是成员属性,那么成员方法该如何实现,那就是函数指针。
对于一台电脑,它有磁盘、显示器、键盘、网卡、显卡等硬件,它们对应的底层不同,那么对应的操作方法也就不同,但它们都是外设,所以每一个设备的核心访问函数都可以是read,write(I/O)。
所有的设备,都可以有自己的read和write,但是它们代码的实现一定是不一样的,所以linux就给它们各自都提供一个struct file。
那么在这所有struct file的上层,就没有任何硬件区别了,这就是linux下一切皆文件的理解。