日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux C:文件描述符、IO重定向、恢复标准输入输出

發布時間:2024/10/14 linux 89 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux C:文件描述符、IO重定向、恢复标准输入输出 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

? ?

一、文件描述符??

二、IO重定向

三、重定向回終端、偽終端

四、恢復標準輸入輸出


? ?

一、文件描述符??

? ? ?在Linux中,文件描述符是一個非負整數的數據類型。是FILE結構體中的一個成員屬性。?每打開或者新建一個文件時,內核都會返回最小的且未被使用的非負整數,即文件描述符。例如,文件描述符 0,1,2,4,5...已經被該進程使用了,那么再打開一個文件返回的文件描述符就是3,再打開一個新文件就是6。如果文件描述符被關閉,那么文件描述符在下一次可能會重新被打開。

? ? ?FILE結構體大致如下

-----------FILE Structure--------- char fbuf[SIZE]; int counter,index.......... 一些其它屬性 int fd; //文件描述符

Linux 為每個進程創建了文件描述符表(fd, 文件指針),其中文件指針,指向了系統級的打開文件表,通過該指針可以獲取到文件偏移量和i-node指針信息,再通過文件偏移量和i-node指針,可以定位到文件系統中的i-node表,從而找到物理硬盤上的文件。換言之,在操作系統之上,通過進程號和文件描述符就可以定位到具體的文件。這個關系是一對多的,因為一個對象可以被多個指針指向,而一個指針只能指向一個對象。這就意味著,多個進程級的文件描述符可能會指向同一個系統級打開文件表,多個打開文件表項可能指向同一個i-node表。

二、IO重定向

在sh進程中有3個用于終端的IO文件流: stdin(標準輸入),stdout(標準輸出),stderr(標準錯誤)。

這3個流實際上指向文件結構體的指針, FILE *?stdin , stdout ,stderr;

它們指向的FILE的區別在于它們的文件描述符分別是STDIN_FILENO, STDOUT_FILENO,STDERR_FILENO分別對應的值是0,1,2。標準輸入默認來源于鍵盤,標準輸出、標準錯誤的目標默認是屏幕。改變它們的來源或者目標就叫IO重定向。對應linux的操作符是? ?"<","1>","2>"。

所以通常程序的缺省情況,fd通常就已經打開了3個,如果想改變輸入流或者輸出流到文件,那么就要關閉對應的文件描述符。當重新open文件時,系統就會返回最小的且未被使用的文件描述符。

例如在filename.txt寫入8878 . ,當關閉文件描述符0時,在打開文件,調用scanf函數就不再從鍵盤中輸入,而把filename.txt中的內容當作輸入。

#include<fcntl.h> #include<stdio.h> #include<stdlib.h> #include <unistd.h> int main(){close(0);int fd = open("filename.txt",O_RDONLY);int item;scanf("%d",&item);printf("format= %d",item); }

關于scanf。當FILE結構體中fbuf為空時,才會向內核中發出read系統調用,通過文件描述符為0 和進程號找到對應的文件,把文件數據讀到fbuf中。所以哪個文件獲取到了文件描述符0,那么標準輸入的來源就是這個文件。同理,哪個文件獲取到了文件描述符1? (2),那么標準輸出(錯誤)的目標就是這個文件。

三、重定向回終端、偽終端

? ? ? 終端和偽終端通常包含屏幕和鍵盤。屏幕輸出前,需要通常保存在/dev/ttyX? 文件下 ,鍵盤輸入后,輸入的內容通常保存在 /dev/pts/# 下。

確定具體文件描述符打開的對應文件

例如在gdb調試代碼時

通過? ?ps? -ef |grep a.out 找到進程號

查詢? ?/proc/[進程號]/fd? 中的內容? (需要root賬號才可以登錄fd目錄)

查看到我的偽終端是:

/dev/pts/2

或者用 tty 命令查看偽終端

yu'shhi標準輸入重定向回鍵盤:

close(0);int fd = open("/dev/pts/2",O_RDONLY);

四、恢復標準輸入輸出

在/dev目錄下有/dev/stdin?文件,stdout文件,stderr文件

注意:標準輸入文件/dev/stdin是個鏈接文件!,其他也一樣,它們存放的是文件描述符地址,鏈接文件類似指針,而標準IO文件類似于雙重指針。文件描述符在Linux系統中也是一個鏈接文件。當close([文件描述符時]),其實刪除的時文件描述符對應的鏈接文件。而/dev/stdin固定鏈接每個 /proc/self/fd/0,當0被刪除了之后,/dev/stdin也就鏈接成了空文件。

也就是說下述代碼得到結果并沒有重新獲得鍵盤輸入

#include<fcntl.h> #include<stdio.h> #include<stdlib.h> #include <unistd.h> int main(){close(0); /**文件 /proc/[pid]/fd/0 消失*****/ int fd = open("filename.txt",O_RDONLY); /**文件 /proc/[pid]/fd/0 鏈接上了filename.txt */ int item;scanf("%d",&item); /*stdin 找到/proc/[pid]/fd/0 中讀數據*/close(0); /*文件 /proc/[pid]/fd/0消失,/dev/stdin為空鏈接*///這樣做的意圖是 /dev/stdin -> /proc/self/0 -> /dev/stdin 嗎??? 顯然目的不是這樣的int fd = open("/dev/stdin",O_RDONLY); /*打開空鏈接文件,并非是終端文件*/scanf("%d",&item); printf("format= %d",item); }

所以如果要保證代碼的通用性,變更stdin鏈接之前需要把終端文件用新的文件描述符保存起來。

(1)? int fd = dup(oldfd);? ?,? ? ?int fd= dup2(oldfd,newfd);

當調用dup函數時,內核在進程中創建一個新的文件描述符,此描述符是當前可用文件描述符的最小數值,這個文件描述符指向oldfd所擁有的文件表項
  dup2和dup的區別就是可以用newfd參數指定新描述符的數值。
  APUE用另外一個種方法說明了這個問題:
  實際上,調用dup(oldfd)等效于,fcntl(oldfd, F_DUPFD, 0)
  而調用dup2(oldfd, newfd)等效于,close(oldfd);fcntl(oldfd, F_DUPFD, newfd);

查看如下代碼:

#include<fcntl.h> #include<stdio.h> #include<string.h> #include<stdlib.h> #include <unistd.h> int main(){int fd2=dup(0) ; //復制文件描述符0對應的表項給fd2 = 3,此時fd2 ,和0 都指向終端close(0); //關閉文件描述符0int fd = open("filename.txt",O_RDONLY); //filename.txt獲取文件描述符0 int item;scanf("%d",&item); //從標準輸入0中讀數據printf("format1= %d\n",item); //輸出filename.txt中讀出來的內容dup2(fd2,0); //復制文件描述符fd2表項給0,此時0重新指向終端,// fopen("/dev/stdin", "r+"); scanf("%d",&item); //同時意味著/dev/stdin 也間接指向了終端printf("format2= %d\n",item); }

總結

以上是生活随笔為你收集整理的Linux C:文件描述符、IO重定向、恢复标准输入输出的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。