文件描述符 文件句柄 重定向

一文件相关的系统调用

C语言标准库函数中有对文件的操作
fopen(),fwrite(),fread(),fclose();等


FILE *fd=fopen("./test.txt","w");                                                                                                                      
      if(fd==NULL)
      {   
          perror("fopen");
          return 1;
      }   
      char * str=(char *)"hello world";
      fwrite(str,strlen(str),1,fd);
      fclose(fd);
操作系统中对文件的操作有系统调用
open(),write(),read(),cloes()等

事实上C语言中的文件操作函数是通过系统调用来实现的。

当我们打开一个文件时,系统会为该文件分配一个文件描述符,这个文件描述符是一个比较小得整数

当操作系统创建一个进程时,会先对这个进程先进行描述,在进行组织

对进程进行描述是用一个结构体,称为进程控制块(PCB),对进程进行组织是用一个链表将这些进程控制块链在一起

一个进程中可以打开多个文件,同样,操作系统对文件也是先进行描述,再进行组织

文件描述也是用一个结构体来,对其进行组织也是用一个链表将其链上去

下面是一个简单的例子
int fd=open("test.txt",O_WRONLY | O_CREAT,0644);                                                                                                         
    if(fd<0)
    {   
        perror("open");exit(1);
    }   
    char * str=(char *)"hello world";
    printf("fd:%d\n",fd);
    write(fd,str,strlen(str));
    close(fd);



这里的文件描述符打印出来是3
这是因为操作系统会为进程默认打开三个文件,分配三个文件描述符0,1,2,分别是标准输入,标准输出,标准错误。

文件描述符默认从空闲的文件描述符中最小的开始分配
close(0);
    close(2);
    int fd_1=open("test1.txt",O_WRONLY|O_CREAT,0644);
    int fd_2=open("test2.txt",O_WRONLY|O_CREAT,0644);
    if(fd_1<0||fd_2<0)
    {   
        perror("open");exit(1);
    }   
    //这里默认从文件描述符中找最小的                                                                                                                         
    printf("fd_1:%d\n",fd_1);
    printf("fd_2:%d\n",fd_2);

操作系统中关于文件的相关系统调用

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

ssize_t read(int fd, void *buf, size_t count);

ssize_t write(int fd, const void *buf, size_t count);

这里注意read()函数
返回值sszie_t 是一个有符号长整型,返回值大于0时,表示本次实际读的字符个数,小于0时表示读取失败,等于0时表示读到文件的结束标志EOF(在Linux下是Ctrl+D,windows下是Ctrl+Z)
说了这么多次文件描述符,那么文件描述符到底是什么呢

二、重定向

看下面代码:
close(1);                                                                                                                                                
    int fd_1=open("test1.txt",O_WRONLY|O_CREAT,0644);
    if(fd_1<0)
    {
        perror("open");exit(1);
    }
    //这里默认从文件描述符中找最小的,所以这里分配的文件描述符为1
    printf("fd_1:%d\n",fd_1);
    //因为printf()函数底层实现还是调用了系统调用fprintf();
    //fprintf(stdout,"%d\n",fd_1)
    //所以这里其实是将内容输出重定向到文件描述符为1的文件中、
    //那么这里就不会看到标准输出上与内容输出
    //而是在我们打开的文件中




      //修改文件句柄,完成重定向                                                                                                                                 
    //dup2(int oldfd,int newfd);这个函数的作用是用newfd是拷贝覆盖了oldfd
    //相当于对newfd文件的操作其实就是oldfd的操作。
    int fd=open("test.txt",O_CREAT | O_WRONLY,0644);
    if(fd<0)
    {   
        perror("open");exit(1);
    }   
    dup2(fd,1);
    printf("fd : %d\n",fd);//就是相当于对文件描述符为1中的问价写其实就是对文件描述符为fd的文件进行操作
    const char * str="nihao shijie\n";
    write(1,str,strlen(str));
    close(fd);

//三种输出“hello world”
//多种打印hello world                                                                                                                                       
   const char * str="hello world\n";
   printf("%s",str);
   write(1,str,strlen(str));
   fprintf(stdout,"%s",str);


当我们在函数结束的时候创建一个子进程呢?
    const char * str_printf="str_printf\n";
    const char * str_fprintf="str_fprintf\n";                                                                                                                
    const char * str_write="str_write\n";

    printf("%s",str_printf);
    fprintf(stdout,"%s",str_fprintf);
    write(1,str_write,strlen(str_write));

    fork(); 

缓冲区刷新格式:
1.无缓冲
2.行缓冲  (显示器)按行刷新换缓冲区
3.全缓冲(文件)缓冲区满了才会进行刷新

当然每一个进程结束会刷新缓冲区

当我们在标准输出上进行输出时是按行刷新自己的缓冲区的,其实是没有什么不同的,因为这里的字符串后面都加了'\n',会自己刷新缓冲区,创建一个子进程后,子进程的缓冲区中为空

因为 输出到一个文件中时是一种全缓冲(等到缓冲区满了才进行刷新)
所以当将其输出重定向到一个文件中的话,是一个全缓冲,父进程将字符串输出后,并没有进行刷新,字符串仍然是父进程的数据,创建一个子进程的话,子进程的缓冲区中就会有字符串,结束时刷新缓冲区,字符串就会被刷新到目标文件,所以会出现两个

上面两个printf()函数和fprintf()函数第层都是调用系统调用write(),但是系统调用却没有缓冲区,所以上面说的缓冲区缓冲区是C库提供的

但是这里的write()是属于系统调用,没有缓冲区,直接输出,没有影响。


猜你喜欢

转载自blog.csdn.net/misszhoudandan/article/details/80301954