文章目錄:
- 1. 檔案描述符
- 1.1 檔案描述符的實質:
- 1.2 檔案描述符的分配規則:
- 1.3 一個行程最大可以開多少個檔案描述符?
- 2. 檔案流指標(FILE)
- 2.1 前言
- 2.2 檔案流指標的本質
- 2.3 深究FILE
- 3. 檔案流指標和檔案描述符的區別
- 4. 重定向
- 4.1 重定向的命令符號
- 4.2 重定向的原理
- 4.3 使用dup2系統呼叫
1. 檔案描述符
檔案描述符就是內核當中 fd_array 陣列的下標,是一個正整數
我們寫出如下代碼,并在代碼最后加上一個回圈,讓代碼不要退出

運行程式,后查看當前行程

如下圖所示:
檔案描述符:
- 0–>標準輸入
- 1–>標準輸出
- 2–>標準錯誤
1.1 檔案描述符的實質:
在行程中有一個結構體指標(struct file_struct* files),指向了一個結構體(struct files_struct),而在這個結構體(struct files_struct)中有一個陣列,這個陣列的下標就是檔案描述符,陣列的每個元素的型別是struct file*,struct file* 這個結構體指標指向 struct file這個結構體(保存了檔案的元資訊),而最終和磁盤打交道的就是struct file這個結構體

1.2 檔案描述符的分配規則:
最小占用原則:在陣列中找到當前沒有被使用的最小的一個下標,作為新的檔案描述符
如下代碼所示,我們關閉了2,會發現fd不是3而是2


1.3 一個行程最大可以開多少個檔案描述符?
行程最大打開檔案描述符個數是由作業系統中一個引數限制的,可以通過命令:
ulimit -a查看到一個open files,open files后面的值就是行程可以打開的最大檔案描述符個數

最大檔案描述符個數更改:
ulimit -n
2. 檔案流指標(FILE)
2.1 前言
我們可以先cd到 /usr/include目錄下,在此目錄下我們可以看到所有的頭檔案

我們在用vim打開stdio.h

此時我們就可以找到FILE

2.2 檔案流指標的本質
- FILE檔案流指標是一個typedef之后的值,本質是一個結構體
- 在“/usr/include/stdio.h”目錄下可以看到
2.3 深究FILE
而我們怎么才能查看FILE這個結構體中的內容呢?
我們可以通過grep "struct _IO_FILE {" . -R命令進行搜索,此時我們會看到,這個結構體的位置在 ./libio.h

此時我們只需vim進入libio.h,在進行搜索即可找到

在struct _IO_FILE這個結構體中,我們可以看到讀緩沖區和寫緩沖區

int _fileno;當中保存的內容就是檔案描述符

在此我們可以更清楚的了解檔案流指標的作業原理,如下圖所示:

之前在行程終止的時候說的重繪緩沖區:指的是C庫當中維護的讀寫緩沖區
借助上圖我們可以理解:_exit()函式之所以不會重繪緩沖區,是因為_exit()函式是內核代碼,直接操作內核結束結束了行程,而此時并不會通知上層的C庫,所以,C庫維護的緩沖區完全在無感知的情況下行程就終結了
3. 檔案流指標和檔案描述符的區別
- 檔案流指標是一個結構體,在結構體內部保存了檔案描述符
- 檔案描述符是一個正整數,其含義為fd_array陣列的下標
- 檔案流指標維護了讀寫緩沖區
4. 重定向
4.1 重定向的命令符號
> :清空重定向,將檔案內容清空之后在重定向
測驗如下:
我們vim一個abc檔案,可以看到abc檔案中的內容如下圖所示:

然后我們使用 ls > abc 命令之后可以看到abc中的內容已經被清空重定向了

>> :追加重定向,直接在檔案的尾部進行重定向
測驗如下:
我們對abc檔案進行追加重定向,可以看到,直接在檔案的尾巴進行了重定向

4.2 重定向的原理
將 fd_array 陣列當中的元素struct file* 指標的指向關系進行修改,改變成為其它的struct file結構體的地址

4.3 使用dup2系統呼叫
int dup2(int oldfd, int newfd);
通過man手冊我們可以對dup2函式進行一些了解,我們會看到這樣一段話

- newfd的值是拷貝于oldfd的值,及newfd的值來源于oldfd
eg:上文重定向原理圖解中的程序可以寫為:dup2(3,0);

(1) 如果必要,使用dup2進行重定向的時候,會先關閉newfd
- 必要:oldfd是正常的檔案描述符
- 如果oldfd不是一個有效的檔案描述符,則不關閉newfd,重定向失敗 eg:dup2(10,0) 沒有檔案描述符10
- 如果oldfd是一個有效的檔案描述符并且和newfd是相同的檔案描述符數值,則dup2什么事情都不有干 eg:dup2(0,0);
(2) 將oldfd的值拷貝給newfd
注意:
一般C庫函式寫入檔案時是全緩沖,而寫入顯示幕是行快取
eg:“\n”==》行緩沖
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/274145.html
標籤:其他

