基础IO(fd与FILE结构体 )

  1. 练习open/read/write/close等文件相关系统调用接口,纵向对比fd与FILE结构体
  2. 对之前编写的自主shell进行修改,使其支持输入/输出/追加重定向

<1>.open函数:
函数原型:

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

参数介绍:
pathname:要打开或创建的目录文件。
flags:打开文件时,可以传入多个参数选项。
参数:

O_RONLY:只读打开。
O_WRONLY:只写打开。
O_RDWR:读写打开
前面三个常量,只能指定一个。
O_CREAT:若文件不存在,则创建它。需要用mode设置权限。
O_APPEND:追加写。
mode:当文件不存在,需要open创建文件,mode表示默认权限 ,否则使用两个参数的open 

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

<2>.write函数:
函数原型:size_t write(int fd,const void *buf,size_t nbyte)
参数:
fd:文件描述符。
buf:指定的缓冲区。即要写入的指针。
nbyte:要写入文件指定的字节数。
返回值:
写入文档成功,返回写的字节数。
错误时返回-1。

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<fcntl.h>
  4 #include<unistd.h>
  5 #include<sys/types.h>
  6 #include<sys/stat.h>
  7 
  8 int main()
  9 {
 10         umask(0);
 11         int fd=open("myfile1",O_WRONLY|O_CREAT,0644);//open函数,0644代表权限
 12         if(fd<0){
 13                 perror("open");
 14                 return 1;
 15                 }
 16         int count=5;
 17         const char*msg="hello world\n";
 18         int len=strlen(msg);
 19         while(count--){
 20                 write(fd,msg,len+1);
 21         }
 22         close(fd);
 23         return 0;
 24 }

这里写图片描述
<3>.read函数:
函数原型:size_t read(int fd,const void *buf,size_t nbyte)
参数:
fd:文件描述符。
buf:指定的缓冲区。
nbyte:要读取文件指定的字节数。
返回值:
成功时返回读取到的字节数(为零表示读到文件描述符),此返回值受文件剩余字节数限制,当返回值小于指定的字节数(比如已经接近文件结尾,或者正在从管道或者终端读取数据,或者read()被信号中断),发生错误时返回-1。

<4>.close函数:
函数原型:
int close(int fd);

该函数只有一个参数,参数表示文件标识符,

返回值:
返回0表示成功
返回-1表示失败

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<fcntl.h>
  5 #include<unistd.h>
  6 #include<string.h>
  7 
  8 int main()
  9 {
 10         int fd=open("myfile1",O_RDONLY);
 11         if(fd<0){
 12                 perror("open");
 13                 return 1;
 14                 }
 15         const char *msg="hello world\n";
 16         char buf[1024];//定义缓冲区
 17         while(1){
 18                 ssize_t s=read(fd,buf,strlen(msg)+1);
 19                 if(s>0){
 20                 printf("%s",buf);
 21         }else
 22         {
 23                 break;
 24                 }
 25         }
 26         close(fd);
 27         return 0;
 28 }

这里写图片描述

纵向对比fd与FILE结构体 :
文件描述符(fd)

我们都知道在Linux下一切皆文件。当然设备也不例外,如果要对某个设备进行操作,就不得不打开此设备文件,打开文件就会获得该文件的文件描述符fd( file discriptor), 它就是一个很小的整数,每个进程在PCB中都有一个指针*files,指向一张表files_struct,表中包含一个指针数组,每个元素都是指向打开文件的指针。文件描述符就是这个表的索引,即为该数组的下标。
这里写图片描述
文件描述符分配规则:在 file_struct数组中,找到当前没有被使用的最小下标,作为一个新的文件描述符。
下面来举例证明:

#include  <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
int main()
{
        //close(0);
        //close(1);
        int fd=open("myfile",O_RDONLY);
        if(fd<0)
        {
                perror("open");
                return 1;
        }
        printf("fd:%d\n",fd);
        close(fd);
        return 0;
}

这里写图片描述

当close(0)时,输出结果为fd:0。
分析图如下:
这里写图片描述
注意:一般情况下,file_struct数组下标的 0,1,2 分别被标准输入(键盘),标准输出(显示器),标准错误(显示器)占用,只有当调用close()函数,关闭掉某个下标 ,fd才会是0或1,或2.若没有被关闭的,fd会是3。
其次,由于数组下标没有负数,所以fd也不会是负数。

所以,通过上面的介绍,可以知道,fd的本质其实就是一个表示数组下标的小整数。
FILE结构体

1、FILE结构体中的成员

缓冲区基址,缓冲区当前指针,缓冲区大小,缓冲区剩余字节数,文件读写方式等。

struct FILE
{
    char *_ptr;//文件输入的下一个位置
    int _cnt;//当前缓冲区的相对位置
    char *_base;//指基础位置(文件的起始位置)
    int _flag;//文件标志
    int _file;//文件的有效性验证
    int _charbuf;//检查缓冲区状况,如果缓冲区则不读取
    int _bufsiz;//文件的大小
    char *_tmpfname;//临时文件名
};

2、(FILE*)文件指针

文件指针指向进程用户区中一个被叫做FILE结构的结构数据。FILE结构包括一个缓冲区和一个文件描述符 。而文件描述符是文件描述符表的一个索引,因此从某种意义上说文件指针就是句柄的句柄(在Windows系统上,文件描述符被称作文件句柄)。
通常,任何程序运行起来之后都会默认的打开三个标准输入流(stdin:键盘),标准输出流(stdout:显示器),标准错误流(stderr:显示器)。

简单来说,fd是一个一个表示数组下标的小整数。FILE为一个结构体,FILE* 为文件指针,指向文件。

文件描述符与文件指针(即指向FILE结构体的指针)区别:
fd是一个表示数组下标的整数,在打开文件的过程中,起到一个索引的作用,进程通过PCB中的文件描述符找到所指向的文件指针file*。
open:文件描述符的操作(如:open)返回的是一个文件描述符(int fd),内核会在每个进程空间中维护一个文件描述符表,此表中的文件描述符来引用。
fopen:流(如:fopen)返回的是一个文件指针(即指向FILE结构体的指针),FILE结构是包含有文件描述符的,fopen可以看做是open(fd直接操作的系统调用)的封装,它的优点是带有I/O缓存。

重定向

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<fcntl.h>
  5 #include<stdlib.h>
  6 
  7 int main()
  8 {
  9         close(1);
 10         int fd=open("myfile",O_WRONLY|O_CREAT,0644);
 11         if(fd<0){
 12                 perror("open");
 13                 return 1;
 14         }
 15         printf("fd:%d\n",fd);
 16         fflush(stdout);
 17         close(fd);
 18         exit(0);
 19 }

这里写图片描述

本该输出到显示器的内容,却输出到了myfile文件中。这种现象就叫做输出重定向。
常见的重定向有

>   会删除原来的内容,写当下输出的内容
>>   直接在原文后面追加新内容
<      输入重定向

上面结果解释:
printf函数是C库当中的IO函数,本该往stdout输出,在执行了close(1),当stdout在底层访问文件时,找到的还是fd:1.但此时fd:1所表示的内容,已经变成了myfile的地址,不再是显示器文件的地址,凡是应该写进标准输出文件的内容,全部被改写到myfile文件中
这里写图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值