目录
0.预备知识 1.系统文件I/O 1.open 2.write/read/close/lseek
2.文件描述符fd 1.[0 & 1 & 2] 2.什么是文件描述符? 3.文件描述符的分配规则 4.重定向 5.使用dup2系统调用 -- 完成重定向 6.FILE
0.预备知识
什么叫做文件呢?
站在系统的角度,能够被input读取,或者能够output写出的设备就叫做文件 狭义文件:普通的磁盘文件 广义文件:显示器,键盘,网卡,声卡,显卡,磁盘,几乎所有的外设,都可以称之为文件 什么是当前路径 ?
当一个进程运行起来的时候,每个进程都会记录自己当前所处的工作路径 C/C++默认会打开三个输入输出流,分别是stdin,stdout,stderr 如何给函数传递标志位?
# define ONE 0x1
# define TWO 0x2
# define THREE 0x4
void show ( int flags)
{
if ( flags & ONE) printf ( "hello one\n" ) ;
if ( flags & TWO) printf ( "hello two\n" ) ;
if ( flags & THREE) printf ( "hello three\n" ) ;
}
int main ( )
{
show ( ONE) ;
show ( TWO) ;
show ( ONE | TWO) ;
show ( ONE | TWO | THREE) ;
show ( ONE | THREE) ;
return 0 ;
}
1.系统文件I/O
1.open
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 追加写
返回值 :
open函数具体使用哪个,和具体应用场景相关
如目标文件不存在,需要open创建,则第三个参数表示创建文件的默认权限 否则,使用两个参数的open
2.write/read/close/lseek
具体使用与open类似,直接man查询 功能类比C文件相关接口即可 C语言库中的f#系列的函数,都是对系统调用的封装
2.文件描述符fd
1.[0 & 1 & 2]
Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错误2
0,1,2对应的物理设备一般是:键盘,显示器,显示器
2.什么是文件描述符?
文件描述符就是从0开始的整数 当打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件
于是就有了file结构体 ,表示一个已经打开的文件对象 而进程执行open系统调用,所以必须让进程和文件关联起来
每个进程都有一个指针files ,指向一张表files_struct ,该表最重要的部分就是包涵一个指针数组,每个元素都是一个指向打开文件的指针 本质上,文件描述符就是该数组的下标
3.文件描述符的分配规则
在files_struct数组当中,找到当前没有被使用的最小的一个下标 ,作为新的文件描述符
4.重定向
int main ( )
{
close ( 1 ) ;
int fd = open ( "myfile" , O_WRONLY | O_CREAT, 0644 ) ;
if ( fd < 0 )
{
perror ( "open" ) ;
return 1 ;
}
printf ( "fd: %d\n" , fd) ;
fflush ( stdout ) ;
close ( fd) ;
exit ( 0 ) ;
}
本来应该输出到显示器上的内容,输出到了文件myfile当中
fd=1 --> 这种现象叫做输出重定向 常见的重定向有:>,>>,< 重定向的本质 :在OS内部,更改fd对应内容的指向
5.使用dup2系统调用 – 完成重定向
把oldfd内容拷贝到newfd --> 最后要和谁一样? --> oldfd
这里拷贝的是file_struct中fd下标对应的file的地址 例子 printf是C库当中的IO函数,一般往stdout中输出,但是stdout底层访问文件的时候,找的还是fd:1
但此时,fd:1下标所表示内容,已经变成了myfile的地址,不再是显示器文件的地址 所以,输出的任何消息都会往文件中写入,进而完成输出重定向
int main ( )
{
int fd = open ( "./log" , O_CREAT | O_RDWR) ;
if ( fd < 0 )
{
perror ( "open" ) ;
return 1 ;
}
close ( 1 ) ;
dup2 ( fd, 1 ) ;
for ( ; ; )
{
char buf[ 1024 ] = { 0 } ;
ssize_t read_size = read ( 0 , buf, sizeof ( buf) - 1 ) ;
if ( read_size < 0 )
{
perror ( "read" ) ;
break ;
}
printf ( "%s" , buf) ;
fflush ( stdout ) ;
}
return 0 ;
}
6.FILE
因为IO相关函数与系统调用接口对应,并且库函数封装系统调用
所以本质 上,访问文件都是通过fd访问的 --> struct File中封装了fd