序言:
前面在Linux 基礎文件IO操作-CSDN博客這篇博客里說了很多函數無論是在語言層還是在系統調用的方面。在調用系統調用open的時候會返回一個整型,在write傳參的時候第一個參數是一個叫fd的東西,這個是什么東西?這篇博客會詳細解釋這個問題。
Ⅰ、文件描述符
什么是文件描述符?當調用open時成功就會返回一個整數這個就是文件描述符(file descriptor
)
一、C語言FILE和文件描述符的關系
在語言層我們并沒有看見過文件描述符,我們在C語言中經常用的是文件指針,好像文件指針和文件描述符在一些功能上是相識的,他們之間有什么關系嗎?
在C語言庫中FILE是一個結構體,它的里邊就包含了文件描述符,也就是說FILE是對fd的一層封裝。下面我們來看一段代碼來證明這一點:
在C語言層對系統調用做封裝,用來使用更加方便和提升代碼的可移植性。
下面我們再來看一段代碼:
1 #include<stdio.h>2 #include<string.h>3 #include<sys/stat.h>4 #include<fcntl.h>5 #include<sys/types.h> 6 7 8 int main()9 {10 int fd1 = open("log1.txt",O_WRONLY|O_CREAT|O_TRUNC);11 int fd2 = open("log2.txt",O_WRONLY|O_CREAT|O_TRUNC);12 int fd3 = open("log3.txt",O_WRONLY|O_CREAT|O_TRUNC);13 int fd4 = open("log4.txt",O_WRONLY|O_CREAT|O_TRUNC);14 15 printf("fd1 = %d\n",fd1);16 printf("fd2 = %d\n",fd2);17 printf("fd3 = %d\n",fd3);18 printf("fd4 = %d\n",fd4);19 return 0;20 }
在這里我們會很奇怪為什么我們打開的文件的文件描述符是從3開始而不是從0。當我們的代碼開始運行的時候有三個文件流會默認打開,在C語言中叫stdin,stdout, stderr ,這三個文件流占據著0 ,1 ,2? 下面我們來證明一下:
1 #include<stdio.h>2 #include<string.h>3 #include<sys/stat.h>4 #include<fcntl.h>5 #include<sys/types.h>6 7 8 int main()9 {10 FILE* fd = fopen("log.txt","w");11 12 printf("stdin = %d\n", stdin->_fileno ); 13 printf("stdout = %d\n", stdout->_fileno );14 printf("stderr = %d\n", stderr->_fileno );15 printf("log.txt = %d\n", fd->_fileno );16 17 18 fclose(fd);19 return 0;20 }
二、為什么要有文件操作符?
上一個博客我們說到我們要對文件進行管理采用 “先組織,再管理” 的思想所以有了struct_file組織各種文件的各種信息,如何去管理這些結構體呢?
再task_struct中會有一個指針指向指針數組,這些指針數組中放著各個struct_file的指針,這個指針數組就叫做文件描述表,數組的下標就是文件描述符,所以文件描述符就是數組的下標,操作系統通過這些文件描述符就可以去管理文件。
三、文件描述符的分配規則
當一個文件打開的時候就會把它的struct_file指針按照最小且沒有被使用的地址存放,這塊地址的下標作為這個文件的fd返回給用戶。
1 #include<stdio.h>2 #include<string.h>3 #include<sys/stat.h>4 #include<fcntl.h>5 #include<sys/types.h>6 7 8 int main()9 {10 fclose(stdin);11 FILE* fd = fopen("log.txt","w");12 printf("log.txt = %d\n", fd->_fileno ); 13 printf("stdout = %d\n", stdout->_fileno );14 printf("stderr = %d\n", stderr->_fileno );15 16 17 fclose(fd);18 return 0;19 }
Ⅱ、重定向操作
一、重定向的本質
在linux中可以通過一些指令“ > ,>>? ,?<”實現重定向操作。我們如何去實現重定向換句話來說重定向的本質是什么?我們在上面看見C語言中的stdin,stdout,stderr 的文件操作符分別是0,1,2,如果我們打開一個新的文件那么它的文件描述符就是 3 ,如果我們能將files_struct array[3]里的地址復制一份給files_struct array[1]里,那么也就相當于文件描述符為1指向的是我們打開的是我們打開的文件,怎么去改變這兩個值呢?我們可以用系統調用dup2。
參數中的oldfd是要復制的地址的fd,而newfd是被復制地址的fd。按照我們上面說的例子那么oldfd是 3 我們打開的文件,而newfd是 fd = 1的這個文件。知道這個系統調用了以后我們可以做一個實驗。
下面看一段代碼:
1 #include<stdio.h>2 #include<string.h>3 #include<sys/stat.h>4 #include<fcntl.h>5 #include<sys/types.h>6 #include<unistd.h>7 8 int main()9 {10 int fd = open("log.txt",O_WRONLY|O_CREAT|O_TRUNC);11 dup2(fd,1);12 close(fd);13 printf("hello dup2\n"); 14 return 0;15 }
為什么我們printf沒有向顯示器上打而是向我們的文件里打呢?我們知道stdin,stdout,stderr分別是鍵盤文件,顯示器文件,顯示器文件,他們是固定的fd,在C語言在分裝的函數比如printf,scanf在函數里封裝了fd,所以他們的fd是固定的,那么我們通過更改fd = 1里的指針我們就可以實現輸出重定向和追加重定向,更改fd = 0里的指針可以實現輸入重定向。綜上所述重定向的本質就是對文件描述符表對下標 0,1的改變。
=========================================================================
本篇關于Linux的文件理解與操作的介紹就暫告段落啦,希望能對大家的學習產生幫助,歡迎各位佬前來支持糾正!!!