目錄
0.接上篇文章
1.粗略的見一下這兩個問題
2.理解重定向?
3.理解緩沖區?
0.接上篇文章
Linux--基礎IO(文件描述符fd)-CSDN博客
1.粗略的見一下這兩個問題
先來了解幾個函數:
?????????
stat()
函數用于獲取指定文件或符號鏈接的元數據。如果文件是一個符號鏈接,stat()
將返回該符號鏈接本身的元數據,而不是它所指向的目標文件的元數據。
? ?fstat()
函數用于獲取已打開文件的元數據。它通常用于在文件描述符已經打開之后獲取文件的元數據。
? ?lstat()
函數與stat()
函數類似,但它專門用于獲取符號鏈接的元數據。如果指定的文件是一個符號鏈接,lstat()
將返回該符號鏈接本身的元數據,而不是它所指向的目標文件的元數據。
fd
:一個已打開的文件描述符。
buf
:一個指向struct stat
的指針,用于存儲符號鏈接的元數據。path
:要檢查的文件或目錄的路徑。????????這三個函數都使用
struct stat
結構來存儲文件的元數據。這個結構包含了許多字段,如文件類型(普通文件、目錄、符號鏈接等)、權限、所有者ID、組ID、大小、時間戳等。具體的字段取決于你的系統和編譯器,但你可以查閱sys/stat.h
頭文件以獲取更多詳細信息。演示:
再來看一段代碼:
????????我們打開文件的時候做了一個操作,colse(1)首先關閉了文件描述符?
1,我們知道文件描述符1,表示的是顯示器文件,而printf&&fprintf都是向顯示器上打印的,現在關閉了顯示器文件,意味著顯示器上不會出現打印的內容。
????????文件描述符1被關閉了,意味著fd1空了出來,那么log.txt將繼承fd1(文件描述符分配規則;查自己的文件描述表,分配最小的沒有被使用的fd),那么現在向fd1中寫就是在向log.txt中寫,所以我們查看到log.txt中的內容就是printf&&fprintf輸出的內容,這就是對文件做重定向(重定向的本質:是在內核中改變文件描述符表特定下標的內容,和上層無關!)
在這段代碼中:我們還需要注意一點,fflush(stdout)刷新stdout,如果不進行此操作,log.txt中是不會有任何內容的,這是為什么呢?
原因是:在struct FILE*這個結構體中存在語言級別的緩沖區,我們在使用printf&&fprintf時,并不是直接通過文件描述符寫入到內核文件緩沖區中,而是先寫到語言級別的緩存區中,再由C語言通過文件描述符,刷新到內核文件緩存區當中,此時外設才能看到輸出的內容,因此fflush(stdout)此時的工作是將stdout緩沖區中的內容通過文件描述符1,刷新到log.txt內核文件緩存區當中去,這時候log.txt中才能看到內容。如果沒有close(fd)這一語句,那么不加刷新也沒關系,進程結束之后,會自動通過fd刷新到文件中。
2.理解重定向?
先認識一個系統調用接口:dup2
??dup2
?的功能是將一個已存在的文件描述符復制到另一個文件描述符,如果目標文件描述符已經打開,則先將其關閉。(本質是文件描述符下標所對應內容的拷貝)。#include <unistd.h> int dup2(int oldfd, int newfd);
1. 標準輸出重定向,由顯示器打印->log.txt打印(接上面例子,我們使用dup2系統調用接口該如何做呢?)
????????也就是我們沒有關閉fd1,那么新打開的log.txt的fd就是3,我們使用了dup2的效果就是,把fd3的內容拷貝給了fd1,也就是說,讓fd1指向了文件log.txt,所以未來向fd1里寫入內容,實際上就是向log.txt中寫入內容,最終只會留下fd3(oldfd)。(fd1和fd3里的地址一樣l)
那么代碼就應該這么寫:
這樣輸出到顯示器的內容就輸出到log.txt了
3.理解緩沖區?
在Linux操作系統中,緩沖區是一個非常重要的概念,主要用于提高I/O(輸入/輸出)操作的效率。以下是關于Linux操作系統中緩沖區的理解:
- 概念:緩沖區是內存中的一塊區域,用于臨時存放數據。當進程需要向外部設備(如磁盤、網絡等)寫入數據時,它不會直接將數據寫入設備,而是先將數據寫入到緩沖區中。同樣,當進程從外部設備讀取數據時,數據也是先從設備讀取到緩沖區,當緩沖區的數據到達某個值的時候,在統一的刷新到進程中。
- 作用:
- 減少對外部設備的直接訪問次數,從而降低I/O操作的開銷。
- 允許進程進行批量數據傳輸,從而提高數據傳輸的效率。
- 通過緩存數據,可以實現對數據的預處理和后處理,如數據壓縮、加密等。
- 刷新策略:Linux中的緩沖區有不同的刷新策略,以適應不同的應用場景。
- 無緩沖:數據一寫入到緩沖區就立即刷新到外部設備。(eg:1.語言級的緩沖區printf/fprintf,2.系統調用fsync)
- 行緩沖:當在輸入或輸出中遇到換行符(
\n
)時,緩沖區會刷新一次。這種策略常用于與終端設備(如顯示器)的交互。- 全緩沖:當緩沖區滿時,數據才會被刷新到外部設備。這種策略常用于寫入磁盤文件等場景。
- 特殊情況(1.進程退出,自動刷新;2強制刷新)
- 與文件系統的關系:在Linux文件系統中,緩沖區也起著重要的作用。當應用程序讀取文件時,內核會將文件數據讀入內核空間緩沖區中,然后再將數據從內核空間緩沖區復制到用戶空間緩沖區中。同樣地,當應用程序向文件寫入數據時,數據也是先寫入到用戶空間緩沖區中,然后再由內核將數據從用戶空間緩沖區復制到內核空間緩沖區,并最終寫入到磁盤上。
- 緩沖區就在struct FILE*結構體中,每一個文件都有自己的緩沖區(這是在語言層面的)
補充示例
????????刷新策略發生改變,看下面的兩段代碼:
第一段代碼及它的運行結果(我們將打印到屏幕的內容重定向到文件中)
第二段代碼及它的運行結果(與第一段代碼不同的是,加入了一個fork函數)
問題:為什么加了fork之后,會打印兩次內容,fork不是只會繼承父進程下面的代碼嗎?為什么C語言庫函數的內容打印了兩次,而系統調用的只打印了一次呢?
????????首先./mytest這個操作是向顯示器文件打印,顯示器文件的刷新策略是行緩沖,現在轉為向普通文件打印,普通文件的刷新策略是全緩沖,由顯示器文件轉向普通文件打印,這里刷新策略就發生了改變。此時printf/fprintf在執行完之后,緩沖區還沒有寫滿(因為是全緩沖),不做刷新,最后fork的時候就出現了父子進程,fork結束后進程就直接退出了,此時父子進程都要執行刷新,所以就打印了兩次內容,而系統調用接口是直接向內核級緩沖區中寫的,所以不存在刷新兩次的問題了。