1. 程式人生 > 其它 >第7、8章學習筆記

第7、8章學習筆記

一、梗概

  • 第七章討論了多種檔案系統;解釋了作業系統中的各種操作級別,包括為檔案儲存準備儲存裝置、核心中的檔案系統支援函式、系統呼叫、檔案流上的 1/O庫函式、使用者命令和各種操作的sh指令碼;系統性概述了各種操作,包括從使用者空間的檔案流讀/寫到核心空間的系統呼叫,直到底層的裝置I/O驅動程式級別;描述了低級別的檔案操作,包括磁碟分割槽、顯示區表的示例程式、檔案系統的格式化分割槽以及掛載磁碟分割槽;介紹了 Linux 系統的EXT檔案系統,包括 EXT2檔案系統的系統資料結構、顯示超級塊、組描述符、塊和索引節點點陣圖以及目錄內容的示例程式。
  • 第八章述瞭如何使用系統呼叫進行檔案操作;解釋了系統呼叫的作用和 Linux 的線上手冊頁;展示瞭如何使用系統呼叫進行檔案操作;列舉並解釋了檔案操作中最常用的系統呼叫;闡明瞭硬連結和符號連結檔案;具體解釋了stat 系統呼叫;基於stat資訊,開發了一個類似於ls 的程式來顯示目錄內容和檔案資訊;接著,講解了open-close-lseek 系統呼叫和檔案描述符;然後,展示瞭如何使用讀寫系統呼叫來讀寫檔案內容;在此基礎上,說明了如何使用系統呼叫來顯示和複製檔案;還演示瞭如何開發選擇性檔案複製程式,其行為類似於一個簡化的Linux dd實用程式。

二、知識點總結

1、檔案操作級別

  • 1)硬體級別
    2)作業系統核心中的檔案系統函式
    3)系統呼叫:使用者模式使用系統呼叫來訪問核心函式。
    4)I/O庫函式
    5)使用者命令
    6)Sh指令碼

2、檔案I/O操作

函式操作:
1)open函式

標頭檔案:#include<fcntl.h>

函式原型:
int open(const char *path, int oflag,........)

引數說明:
path:一般指需要開啟或者建立的檔名字
oflag:常用的標誌(O_RDONLY、O_WRONLY、O_RDWR、O_CRAET、O_TRUNC)

2)close函式

標頭檔案:#include<unistd.h>

函式原型:int close(int fd)

引數說明:fd:需要關閉的檔案描述符

3)lseek函式

標頭檔案:#include<unistd.h>

函式原型:
off_t lseek(int fd, off_t offset, int whence)

引數說明:
fd: 需要操作檔案的檔案描述符
offset:與whence有關具體如下:
whence = SEEK_SET 檔案的偏移量設定位距檔案的開始處的offset個位元組
whence = SEEK_CUR 檔案的偏移量設定為當前值加上offset個位元組
whence = SEEK_END 將檔案的偏移量設定成檔案長度加上offset個位元組
返回值:返回新的檔案偏移量

4)read函式

標頭檔案:#include<unistd.h>

函式原型:
ssize_t read(int fd, void *buf, size_t nbytes )

引數說明:
fd: 需要讀取檔案的檔案描述符
buf:讀取的資料存入buf中
nbytes:需要讀取的位元組數

5)write函式

標頭檔案:#include<unsitd.h>

函式原型:
ssize_t write(int fd, void *buf, size_t nbytes)

引數說明:
fd: 需要寫入檔案的檔案描述符
buf:儲存需要寫資料的buf
nbytes:需要寫入檔案的位元組數

3、使用系統呼叫進行檔案操作

  • 我們可以通過兩種方式訪問檔案,一種是linux的作業系統介面,即系統呼叫,另一種是GNU在對系統呼叫進行封裝優化處理後的標準輸入輸出函式<stdio.h>。
    針對輸入輸出操作直接使用底層系統呼叫時的效率很低,因為在執行系統呼叫函式時,Linux必須實現使用者態和核心態之間的切換,這種開銷是非常大的,庫函式通過設定緩衝區每次讀寫大量資料而減少系統呼叫次數。
    系統呼叫(系統呼叫是作業系統提供給使用者程式的一組“特殊”函式介面,使用者通過這組介面獲得作業系統提供的服務)中操作I/O的函式,都是針對檔案描述符的。
  • 通過檔案描述符可以直接對相應檔案進行操作,如:open、close、write、read、ioctl
    //#define STDIN_FILENO 0 //標準輸入的檔案描述符
    //#define STDOUT_FIFENO 1 //標準輸出的檔案描述符
    //#define STDERR_FILENO 2 //標準錯誤的檔案描述符
    程式執行起來後這三個檔案描述符是預設開啟的

4、連結檔案

  • 在linux系統中有種檔案是連結檔案,可以為解決檔案的共享使用。連結的方式可以分為兩種,一種是硬連結(Hard Link),另一種是軟連結或者也稱為符號連結(Symbolic Link)。可使用ll命令檢視哪些是連結檔案。
    硬連結是指通過索引節點來進行連結。在Linux的檔案系統中,儲存在磁碟分割槽中的檔案不管是什麼型別都會給它分配一個編號,這個編號被稱為索引節點編號(Inode Index)或者Inode,它是檔案或者目錄在一個檔案系統中的唯一標識,檔案的實際資料放置在資料區域(data block),它儲存著檔案重要引數資訊,也就是元資料 (metadata),比如建立時間、修改時間、檔案大小、屬主、歸屬的使用者組、讀寫許可權、資料所在block號等。如圖所示:
  • 在Linux系統中,多個檔名指向同一索引節點(Inode)是正常且允許的。一般這種連結就稱為硬連結。硬連結的作用之一是允許一個檔案擁有多個有效路徑名,這樣使用者就可以建立硬連結到重要的檔案,以防止“誤刪”源資料(很多硬體,如netapp儲存中的快照功能就應用了這個原理,增加一個快照就多了一個硬連結)。
    軟連結(也叫符號連結),類似於windows系統中的快捷方式,與硬連結不同,軟連結就是一個普通檔案,只是資料塊內容有點特殊,檔案使用者資料塊中存放的內容是另一檔案的路徑名的指向,通過這個方式可以快速定位到軟連線所指向的原始檔實體。軟連結可對檔案或目錄建立。
    軟連結作用:
    便於檔案的管理,比如把一個複雜路徑下的檔案連結到一個簡單路徑下方便使用者訪問。
    節省空間解決空間不足問題,某個檔案系統空間已經用完了,但是現在必須在該檔案系統下建立一個新的目錄並存儲大量的檔案,那麼可以把另一個剩餘空間較多的檔案系統中的目錄連結到該檔案系統中。
    刪除軟連結並不影響被指向的檔案,但若被指向的原檔案被刪除,則相關軟連線就變成了死連結。

5、系統呼叫函式

write系統呼叫
write,就是把緩衝區的資料寫入檔案中。注意,這裡的檔案時廣泛意義的檔案,比如寫入磁碟、寫入印表機等等。
Linux 中write()的函式原型:
size_t write(int fildes, const void *buf, size_t nbytes);

引數說明:
fildes:檔案描述符,標識了要寫入的目標檔案。例如:fildes的值為1,就像標準輸出寫資料,也就是在顯示屏上顯示資料;如果為 2 ,則想標註錯誤寫資料。
*buf:待寫入的檔案,是一個字串指標。
nbytes:要寫入的字元數。

函式返回值:size_t 返回成功寫入檔案的字元數。需要指出的是,write可能會報告說他寫入的位元組比你所要求的少。這並不一定是個錯誤。在程式中,你需要檢查
error已發現錯誤,然後再次呼叫write寫入剩餘的資料。

read系統呼叫
系統呼叫read是從檔案中讀出資料。要讀取的檔案用檔案描述符標識,資料讀入一個事先定義好的緩衝區。他返回實際讀入的位元組數。
Linux中read的函式原型:
size_t read(int fildes, void *buf, size_t nbytes);

引數說明:
fildes:檔案描述符,標識要讀取的檔案。如果為0,則從標準輸入讀資料。類似於scanf()的功能。
*buf:緩衝區,用來儲存讀入的資料。
nbytes:要讀取的字元數。

返回值:size_t返回成功讀取的字元數,它可能會小於請求的位元組數。

系統呼叫open的作用是開啟一個檔案,並返回這個檔案的描述符。
簡單地說,open建立了一條到檔案或裝置的訪問路徑。如果操作成功,它將返回一個檔案描述符,read和write等系統呼叫使用該檔案描述符對檔案或
裝置進行操作。這個檔案描述符是唯一的,他不會和任何其他執行中的程序共享。如果兩個程式同時開啟一個檔案,會得到兩個不同的問價描述符。

Linux中open的函式原型有兩個:
int open(const char *path, int oflags);
int open(const char *path, int oflags, mode_t mode );

引數說明:
path:準備開啟的檔案或裝置名字。
oflags:指出要開啟檔案的訪問模式。open呼叫必須指定如下所示的檔案訪問模式之一:

open呼叫可以在oflags引數中包括下列可選模式的組合(用”按位或“操作):
O_APPEDN: 把寫入資料追加在檔案的末尾。
O_TRUNC: 把檔案長度設為零,丟棄以後的內容。
O_CREAT: 如果需要,就按引數mode中給出的訪問模式建立檔案。
O_EXCL: 與O_CREAT一起呼叫,確保呼叫者創建出檔案。使用這個模式可防止兩個程式同時建立一個檔案,如果檔案已經存在,open呼叫將失敗。

三、最有收穫的內容

  • 這次學習,我最有收穫的內容是加深了對系統呼叫的理解。簡單來說,系統呼叫就是使用者程式和硬體裝置之間的橋樑。使用者程式在需要的時候,通過系統呼叫來使用硬體裝置。
    1)使用者程式通過系統呼叫來使用硬體,而不用關心具體的硬體裝置,這樣大大簡化了使用者程式的開發。
    比如:使用者程式通過write()系統呼叫就可以將資料寫入檔案,而不必關心檔案是在磁碟上還是軟盤上,或者其他儲存上。

  • 2)系統呼叫使得使用者程式有更好的可移植性。
    只要作業系統提供的系統呼叫介面相同,使用者程式就可在不用修改的情況下,從一個系統遷移到另一個作業系統。

  • 3)系統呼叫使得核心能更好的管理使用者程式,增強了系統的穩定性。
    因為系統呼叫是核心實現的,核心通過系統呼叫來控制開放什麼功能及什麼許可權給使用者程式。
    這樣可以避免使用者程式不正確的使用硬體裝置,從而破壞了其他程式。

  • 4)系統呼叫有效的分離了使用者程式和核心的開發。
    使用者程式只需關心繫統呼叫API,通過這些API來開發自己的應用,不用關心API的具體實現。
    核心則只要關心繫統呼叫API的實現,而不必管它們是被如何呼叫的。

四、問題與解決思路

1、給定檔案路徑“/home/hello”,作業系統時如何找到該檔案的位置?
答:1)查詢根目錄的目錄項。Linux有規定,根目錄的目錄項必須存放在2號inode中。
2)根目錄的目錄項中存著根目錄下的子目錄目錄項和檔案的資料塊資訊。通過根目錄的目錄項可以找到home對應的inode。
3)根據home對應的inode找到home的目錄項。
4)在home目錄項中找到hello檔案的inode。
5)根據hello檔案的inode中的資料塊指標找到儲存有hello檔案內容的資料塊。

2、系統呼叫與普通過程呼叫的區別是什麼?
相同點:
改變指令流程
重複執行和公用
改變指令流程後需要返回原處

不同點:
系統呼叫是動態呼叫,而CALL呼叫方式是靜態呼叫;
執行狀態不同
進入方式不同
與程序排程的關係不同:
巢狀或遞迴呼叫

1) 系統呼叫是動態呼叫,而CALL呼叫方式是靜態呼叫;
系統呼叫是動態呼叫,程式中不包含被呼叫程式碼
好處:
(1)使用者程式長度縮短
(2)當OS升級時,呼叫方不必改變
系統呼叫方式的呼叫地址和返回地址都是不固定的:系統呼叫指令中不包含呼叫地址,只包含功能號;系統呼叫返回指令中也不包含返回地址,通過棧儲存和彈出返回地址。
CALL呼叫方式是靜態呼叫:被呼叫程式碼與呼叫程式碼在同一程式之內。CALL呼叫方式,其呼叫地址是固定的,包含在呼叫語句中

五、實踐內容

1、顯示檔案內容
該程式功能相當於linux cat命令

結果: