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\n", buf);

    //设置文件的偏移量 该偏移量存在于 文件表项中
    //返回当前偏移量距离文件头的字节数
    //这里相当于 获取当前的 文件偏移量
    off_t len = lseek(fd, 0, SEEK_CUR);
    printf("offset = %d\n", (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\n", (int)len);

    char buf[1024] = {0};
    read(fd, buf, 5);
    printf("buf: %s\n", buf);

    len = lseek(fd, 0, SEEK_CUR);
    printf("offset = %d\n", (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\n", (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\n", (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\n", (int)len);

    write(fd, "world", strlen("world"));

    close(fd);

 

 

  

0723------Linux基础----------文件 IO之文件的打开,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。