半生已过

导航

C/CPP文件操作(1)-fopen和open比较

1. fopen和open比较

  不多说,我们先来看下下面的两段代码:

    open系列函数:

 1             int main(int argc, char *argv[])
 2             {
 3                 int fd;
 4                 char buf[32];
 5                 int size = sizeof(buf);
 6                 fd = open("/home/liujun/Work/Study/CPP/File/test.txt", O_RDONLY);
 7                 if (fd < 0) {
 8                     printf("Failed to open file \n");
 9                 }
10                 memset(buf, 0, size); // 特别重要,避免乱码
11                 read(fd, buf, size - 1); // 要小于buf的size,避免出现乱码
12                 close(fd);
13                 printf("************ %s", buf);
14                 return 0;
15             }

    fopen系列函数:

            int main(int argc, char *argv[])
            {
                FILE *fp;
                char buf[32];
                int size = sizeof(buf);
                fp = fopen("/home/liujun/Work/Study/CPP/File/test.txt", "rb");
                if (fp == nullptr) {
                    printf("Failed to open file \n");
                }
            
                memset(buf, 0, size); // 特别重要,避免乱码
                fread(buf, size - 1, 1, fp);
                fclose(fp);
                printf("************ %s", buf);
                return 0;
            }

    上述两段代码的作用和逻辑几乎一模一样,都是从一个文件里面读取信息并打印出来,虽然使用的逻辑不一样,但是这两个系列的函数却有着很大的不同,主要有一下几点

      open是系统调用,返回的是文件句柄(后面会讲述什么是文件句柄)

      fopen是ANSIC标准中的C语言库函数,是对open的封装(Linux下),所以fopen可移植,open不能,返回指向FILE的文件指针

      fopen在用户态下就有缓存机制,因此在进行read和write的时候减少了用户态和内核态的切换,open没有缓存机制,每次读操作都直接从文件系统中获取数据,每次都需要进行内核态和用户态的切换

2. 文件描述符和文件指针

  文件描述符:当我们调用open打开一个文件时,open会返回一个文件描述符fd,fd只是一个小整数,起到一个索引的作用。每个进程在PCB(Process Control Block)即进程控制块中都保存着一份文件描述符表,文件描述符就是这个表的索引,文件描述表中每个表项都有一个指向已打开文件的指针(该指针指向file结构体),现在我们明确一下:已打开的文件在内核中用file结构体表示,文件描述符表中的指针指向file结构体,file结构体如下所示:

 1         struct file {
 2               mode_t f_mode;  // 文件模式,是读是写
 3               loff_t f_pos;   // 当前读写位置
 4               unsigned short f_flags;
 5               unsigned short f_count;
 6               off_t f_reada;
 7               struct file *f_next, *f_prev;
 8               int f_owner;    /* pid or -pgrp where SIGIO should be sent */
 9               struct inode * f_inode;
10               struct file_operations * f_op;
11               unsigned long f_version;
12               void *private_data;  /* needed for tty driver, and maybe others */
13             };

  文件指针:当我们调用fopen打开一个文件时,fopen会返回一个文件指针,该指针指向进程用户区中的一个被称为FILE结构的数据结构,该结构体包含所打开文件的文件描述符和其它的缓存级位置信息,具体如下图所示。

 1         struct FILE
 2         {
 3             char *_ptr;//文件输入的下一个位置
 4             int _cnt;//当前缓冲区的相对位置
 5             char *_base;//指基础位置(文件的起始位置)
 6             int _flag;//文件标志
 7             int _file;//文件描述符
 8             int _charbuf;//检查缓冲区状况,如果缓冲区则不读取
 9             int _bufsiz;//文件的大小
10             char *_tmpfname;//临时文件名
11         };

  FILE包含文件描述符,或者说是对文件描述符的一种封装,且两者可以相互转化

    int fileno(FILE *stream);  // FILE -> fd

    FILE *fdopen(int fd, const char *mode); fd -> FILE

posted on 2021-04-20 08:42  半生已过  阅读(721)  评论(0编辑  收藏  举报