zoukankan      html  css  js  c++  java
  • 0723------Linux基础----------文件 IO之文件的打开

    1.文件的打开 

      1.1 open 和 fopen 。open 返回的是文件描述符,而fopen 返回的是文件指针,二者的第二个参数也不同,一个是宏定义的,一个是字符串。因此在书写的时候要特别注意。

      int fd = open("test.txt", O_RDONLY);
      FILE *fp = fopen("test.txt", "r");

      1.2 FILE * 和 fd 之间的转化

        1.2.1 从FILE *  转化成 fd。 fileno函数用于将一个文件指针转化成文件描述符,此时就可以使用linux的函数。

     FILE *fp = fopen("test.txt", "r");
     int fd = fileno(fp);  

        1.2.2 从fd 转化成 FILE * 。 fdopen函数用于将一个文件描述符转化成指针,此时就可以使用标准的文件函数。这里fp文件指针的打开模式要和fd文件描述符的打开模式吻合,即只读都是只读。

    int fd = open("test.txt", O_RDONLY);
    FILE *fp = fdopen(fd, "r");

      1.3 常用的open标志组合:

        a) O_RDONLY:代表只读

        b) O_WRONLY | O_CREAT:以只写方式打开,文件不存在则创建;

        c) O_WRONLY | O_CREAT | O_APPEND:只写打开,文件不存在则创建,文件存在则进行追加;

        d) O_WRONLY | O_CREAT | O_TRUNC:只写打开,不存在则创建,文件存在则清空;

        e) O_WRONLY | O_CREAT | O_EXCL:只写打开,不存在则创建,文件存在则打开失败。

      1.4 文件指针 stdin, stdout,stderr 在内部一定是调用了STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO这三个文件描述符(因为linux底层是用文件描述符实现的)。

    2.进程打开一个文件描述符涉及到的数据结构

      2.1 Linux进程打开一个文件描述符,涉及到三个数据结构:

        a)  进程表项归单个进程所有记录该进程打开的所有的文件描述符。

        b)  文件表项由内核管理,可对应一次打开文件操作,里面记录打开文件的标志、文件偏移量以及指向文件的指针,以及该结构的引用计数(此时有多少个fd指向它)。

        c)  V节点项,每项对应一个文件,记录着该文件的信息(大小、创建时间、修改时间、所有者、权限)。

      2.2 打开文件时三个数据结构的不同情形:

        a) 一个进程打开两个不同的文件,进程表项 1 个,文件表项 2 个,V结点 2 个;

        b) 一个进程两次打开同一个文件,进程表项 1 个,文件表项 2 个(二者不共享文件偏移量,因此读写不会干扰),V结点 1 个;

        c) 两个进程打开同一文件,进程表项 2 个, 文件表项 2 个, V结点 1 个;

         d) 一个进程打开一个文件,然后用dup 复制了一个文件描述符,此时,进程表项 1 个, 文件表项 1 个(其中引用计数为 2,这与fork一个子进程相同), V结点 1 个。

    3.lseek函数

      3.1 lseek 函数用于为一个打开的文件设置当前文件偏移量, 这个当前文件偏移量属性存在于文件表项里面,每一个打开的文件描述符都和一个当前文件偏移量相关联。本例用于返回当前偏移量的值。

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #define ERR_EXIT(m) 
        do { 
            perror(m);
            exit(EXIT_FAILURE);
        }while(0)
    /*
     * lseek 函数
     *
     */
    
    
    
    int main(int argc, const char *argv[])
    {
        int fd = open("test.txt", O_RDONLY);
        if(fd == -1){
            ERR_EXIT("open");
        }
        char buf[1024] = {0};
        read(fd, buf, 5);
        printf("buf: %s
    ", buf);
    
        //设置文件的偏移量 该偏移量存在于 文件表项中
        //返回当前偏移量距离文件头的字节数
        //这里相当于 获取当前的 文件偏移量
        off_t len = lseek(fd, 0, SEEK_CUR);
        printf("offset = %d
    ", (int)len);
    
        return 0;
    }

      3.2 文件通常的读写操作都是从当前文件偏移量开始的。本例中,先将打开的文件的偏移量设置为后移6个字节的值,那么接下来read的时候就从开始当前文件偏移量处(本例中为6)读取。

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #define ERR_EXIT(m) 
        do { 
            perror(m);
            exit(EXIT_FAILURE);
        }while(0)
    /*
     * lseek 函数
     *
     */
    
    int main(int argc, const char *argv[])
    {
        int fd = open("test.txt", O_RDONLY);
        if(fd == -1){
            ERR_EXIT("open");
        }
        off_t len = lseek(fd, 6, SEEK_CUR); //将当前的偏移量设置为 当前偏移量+6
        printf("offset = %d
    ", (int)len);
    
        char buf[1024] = {0};
        read(fd, buf, 5);
        printf("buf: %s
    ", buf);
    
        len = lseek(fd, 0, SEEK_CUR);
        printf("offset = %d
    ", (int)len);
        return 0;
    }
    

      3.3 lseek 还可以获取文件的大小。这里用 od -c filename 查看文件的内容 可以看到文件的大小,注意左边的是8进制。

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #define ERR_EXIT(m) 
        do { 
            perror(m);
            exit(EXIT_FAILURE);
        }while(0)
    /*
     * lseek 函数
     * 获取文件的大小
     */
    
    int main(int argc, const char *argv[])
    {
        int fd = open("test.txt", O_RDONLY);
        if(fd == -1){
            ERR_EXIT("open");
        }
        off_t len = lseek(fd, 0, SEEK_END);// 设置偏移量为 SEEK_END
        printf("offset = %d
    ", (int)len);
    
        return 0;
    }
    

      

       3.4 lseek 设置文件偏移量时,如果当前没有数据,就写0。

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #define ERR_EXIT(m) 
        do { 
            perror(m);
            exit(EXIT_FAILURE);
        }while(0)
    /*
     */
    
    int main(int argc, const char *argv[])
    {
        int fd = open("test.txt", O_WRONLY | O_CREAT | O_TRUNC);
        if(fd == -1){
            ERR_EXIT("open");
        }
        write(fd, "hello", strlen("hello"));
    
        off_t len = lseek(fd, 10, SEEK_CUR);
        printf("offset = %d
    ", (int)len);
    
        write(fd, "world", strlen("world"));
    
        close(fd);
        return 0;
    }
    

      

      3.5 文件空洞

        3.5.1 什么是文件空洞? 当文件偏移量超过文件大小的时候,就产生了文件空洞,它被记录在文件信息中,但是在磁盘上并不占据过多地的磁盘空间。例如我们在文件中偏移1G的大小,那么在文件信息中就记录了 1G 的空洞,但是在磁盘上并不占据实际空间,如下图所示。

        3.5.2 程序示例和程序运行后的文件信息和磁盘信息。

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #define ERR_EXIT(m) 
        do { 
            perror(m);
            exit(EXIT_FAILURE);
        }while(0)
    /*
     * 文件空洞
     *
     */
    
    
    int main(int argc, const char *argv[])
    {
        int fd = open("test.txt", O_WRONLY | O_CREAT | O_TRUNC);
        if(fd == -1){
            ERR_EXIT("open");
        }
        char buf[] = "hello";
        write(fd, buf, strlen(buf));
    
        off_t len = lseek(fd, 1024*1024*1024, SEEK_CUR);
        printf("OFF_SET = %d
    ", (int)len);
    
        write(fd, "world", strlen("world"));
    
        close(fd);
    

     

      

  • 相关阅读:
    github上fork的项目,如何同步原作者更新的内容?
    设计模式-简单工厂模式详解
    设计模式-建造者模式详解
    设计模式-原型模式详解
    设计模式-单例模式详解
    SqlServer断开所有连接
    Winform重写键盘按键事件
    从拖拉控件编程到面向设计编程(一)
    Springboot vue 前后分离 跨域 Activiti6 工作流 集成代码生成器 shiro权限
    java 微信自定义菜单 java微信接口开发 公众平台 SSM redis shiro 多数据源
  • 原文地址:https://www.cnblogs.com/monicalee/p/3864213.html
Copyright © 2011-2022 走看看