linux系统编程之文件与I/O(五):文件的内核结构file和dup实现重定向

一、打开文件内核数据结构

1、一个进程打开两个文件


文件状态标志:读、写、追加、同步、非阻塞等


2、一个进程两次打开同一文件


3、两个进程打开同一文件


示例程序:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/*************************************************************************
    > File Name: file_share.c
    > Author: Simba
    > Mail: dameng34@163.com
    > Created Time: Sat 23 Feb 2013 02:34:02 PM CST
 ************************************************************************/

#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>

#define ERR_EXIT(m) \
     do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    }  while( 0)

int main( int argc,  char *argv[])
{
     int fd1, fd2;
     char buf1[ 1024] = { 0};
     char buf2[ 1024] = { 0};
     /* 进程控制块PCB
     * struct task {
     * ...
     * struct files_struct *files;
     * }
     * 同一个进程两次打开同一个文件,一个进程拥有的一个文件描述符表其中一个fd索引对应的指针指向一个
     * 文件表(包括文件状态(读写追加同步非阻塞等),当前文件偏移量,
     * 文件引用次数(当有两个fd指向同个文件表时引用计数为2,见dup,也可用于重定向),
     * 文件操作指针, V节点指针等)不共享,
     * V节点表(包括V节点信息(struct stat), i节点信息等)共享
     */

     /* 两个进程打开同一个文件的情况与上类同*/
    fd1 = open( "test.txt", O_RDONLY);
     if (fd1 == - 1)
        ERR_EXIT( "open error");
    read(fd1, buf1,  5);
    printf( "buf1=%s\n", buf1);


    fd2 = open( "test.txt", O_RDWR);
     if (fd2 == - 1)
        ERR_EXIT( "open error");
    read(fd2, buf2,  5);
    printf( "buf2=%s\n", buf2);
    write(fd2,  "AAAAA"5);

    memset(buf1,  0sizeof(buf1));
    read(fd1, buf1,  5);
    printf( "buf1=%s\n", buf1);
    close(fd1);
    close(fd2);

     return  0;
}


假设test.txt文件的内容是 ABCDEhello

测试如下:

simba@ubuntu:~/Documents/code/linux_programming/APUE/File_IO$ ./file_share 
buf1=ABCDE
buf2=ABCDE
buf1=AAAAA

test.txt文件内容变成 ABCDEAAAAA

分析:由上图分析可知,一个进程两次打开同一文件,文件表是不共享的,即各有自己的文件偏移量和打开文件标志,所以两次read不同的fd都是从头开始读取,但V节点表是共享的,在fd2写入(同个文件表的read和write是共享偏移的)更改了inode指向的硬盘数据块,再次read fd1得到的也是更改后的值。


二、I/O重定向



当我们执行了dup(3)之后,系统选择一个空闲的文件描述符即4,这样就有两个文件描述符指向同个文件表,所以引用计数为2。利用dup等函数可以进行重定向的步骤是先close输入输出文件描述符,然后执行dup(fd), 这样输入输出文件描述符也指向fd指向的文件,这样就实现了重定向。此外dup2, fcntl 函数也可以实现,其实不使用这些函数,而直接close(0/1/2)完再open也可以实现。如下使用cat命令实现复制文件的功能:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/*************************************************************************
    > File Name: process_.c
    > Author: Simba
    > Mail: dameng34@163.com
    > Created Time: Sat 23 Feb 2013 02:34:02 PM CST
 ************************************************************************/

#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<signal.h>
#define ERR_EXIT(m) \
     do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    }  while( 0)

int main( int argc,  char *argv[])
{
    close( 0);
    open( "Makefile", O_RDONLY);
    close( 1);
    open( "test.txt", O_WRONLY | O_CREAT | O_TRUNC,  0664);

    execlp( "cat""cat"NULL);

     return  0;
}
现在标准输入是文件Makefile,标准输出是文件test.txt ,将当前进程替换成cat,则cat会从标准输入读而后输出到标准输出,即完成了copy的功能。


dup/fcntl 函数示例程序如下:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/*************************************************************************
    > File Name: file_dup.c
    > Author: Simba
    > Mail: dameng34@163.com
    > Created Time: Sat 23 Feb 2013 02:34:02 PM CST
 ************************************************************************/

#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>

#define ERR_EXIT(m) \
     do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    }  while( 0)

/* dup dup2 fcntl */
int main( int argc,  char *argv[])
{
     int fd;
    fd = open( "test2.txt", O_WRONLY);
     if (fd == - 1)
        ERR_EXIT( "open error");
     /*
        close(1);
        dup(fd);
    */

     //  dup2(fd, 1);

    close( 1);
     if (fcntl(fd, F_DUPFD,  0) <  0//从0开始搜索可用的fd
        ERR_EXIT( "fcntl error");
    printf( "hello\n");  // 输出重定向到test2.txt
     return  0;
}


参考:《APUE》

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页