歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> 關於Linux

linux系統編程之文件與I/O(五) 文件的內核結構file和實現重定向

一、打開文件內核數據結構

1、一個進程打開兩個文件

文件狀態標志:讀、寫、追加、同步、非阻塞等

2、一個進程兩次打開同一文件

3、兩個進程打開同一文件

示例程序:

/*************************************************************************
> File Name: file_share.c
> Author: Simba
> Mail: [email protected]
> 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, 0, sizeof(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=AAAA

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命令實現復制文件的功能:

/*************************************************************************
> File Name: process_.c
> Author: Simba
> Mail: [email protected]
> 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,標准輸出是文件Makefile2,將當前進程替換成cat,則cat會從標准輸入讀而後輸出到標准輸出,即完成了copy的功能。

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

/*************************************************************************
> File Name: file_dup.c
> Author: Simba
> Mail: [email protected]
> 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;
}
Copyright © Linux教程網 All Rights Reserved