實驗四 文件系統
一、實驗目的
1、 熟悉Linux文件系統的文件和目錄結構,掌握Linux文件系統的基本特征;
2、 模擬實現Linux文件系統的簡單I/O流操作:備份文件。
二、實驗內容
1、 瀏覽Linux系統根目錄下的子目錄,熟悉每個目錄的文件和功能;
2、 設計程序模擬實現Linux文件系統的簡單I/O流操作:備份文件。
三、實驗原理
1、 Linux各種發行版的目錄結構基本一致,各個目錄簡單介紹如下:
目錄 |
描述 |
/ |
根目錄 |
/bin |
做為基礎系統所需要的最基礎的命令就是放在這里。比如 ls、cp、mkdir等命令;功能和/usr/bin類似,這個目錄中的文件都是可執行的,普通用戶都可以使用的命令。 |
/boot |
Linux的內核及引導系統程序所需要的文件,比如 vmlinuz initrd.img 文件都位於這個目錄中。在一般情況下,GRUB或LILO系統引導管理器也位於這個目錄;啟動裝載文件存放位置,如kernels,initrd,grub。一般是一個獨立的分區。 |
/dev |
一些必要的設備,聲卡、磁盤等。還有如 /dev/null. /dev/console /dev/zero /dev/full 等。 |
/etc |
系統的配置文件存放地. 一些服務器的配置文件也在這里;比如用戶帳號及密碼配置文件; /etc/opt:/opt對應的配置文件 /etc/X11:Xwindows系統配置文件 /etc/xml:XML配置文件 …… |
/home |
用戶工作目錄,和個人配置文件,如個人環境變量等,所有的賬號分配一個工作目錄。一般是一個獨立的分區。 |
/lib |
庫文件存放地。bin和sbin需要的庫文件。類似windows的DLL。 |
/media |
可拆卸的媒介掛載點,如CD-ROMs、移動硬盤、U盤,系統默認會掛載到這里來。 |
/mnt |
臨時掛載文件系統。這個目錄一般是用於存放掛載儲存設備的掛載目錄的,比如有cdrom 等目錄。可以參看/etc/fstab的定義。 |
/opt |
可選的應用程序包。 |
/proc |
操作系統運行時,進程(正在運行中的程序)信息及內核信息(比如cpu、硬盤分區、內存信息等)存放在這里。/proc目錄偽裝的文件系統proc的掛載目錄,proc並不是真正的文件系統,它的定義可以參見 /etc/fstab 。 |
/root |
Root用戶的工作目錄 |
/sbin |
和bin類似,是一些可執行文件,不過不是所有用戶都需要的,一般是系統管理所需要使用得到的。 |
/tmp |
系統的臨時文件,一般系統重啟不會被保存。 |
/usr |
包含了系統用戶工具和程序。 /usr/bin:非必須的普通用戶可執行命令 /usr/include:標准頭文件 /usr/lib:/usr/bin/ 和 /usr/sbin/的庫文件 /usr/sbin:非必須的可執行文件 /usr/src:內核源碼 /usr/X11R6:X Window System, Version 11, Release 6. |
/srv |
該目錄存放一些服務啟動之后需要提取的數據 |
2、 Linux的文件結構是單個的樹狀結構.可以用tree進行展示。文件操作命令見附錄1,
3、 Linux文件系統:Linux 中允許眾多不同的文件系統共存,如 ext2, ext3, vfat 等。通過使用同一套文件 I/O 系統 調用即可對 Linux 中的任意文件進行操作而無需考慮其所在的具體文件系統格式;更進一步,對文件的 操作可以跨文件系統而執行。“一切皆是文件”是 Unix/Linux 的基本哲學之一。不僅普通的文件,目錄、字符設備、塊設備、 套接字等在 Unix/Linux 中都是以文件被對待;它們雖然類型不同,但是對其提供的卻是同一套操作界面。
4、 虛擬文件系統(Virtual File System, 簡稱 VFS), 是 Linux 內核中的一個軟件層,用於給用戶空間的程序提供文件系統接口;同時,它也提供了內核中的一個 抽象功能,允許不同的文件系統共存。系統中所有的文件系統不但依賴 VFS 共存,而且也依靠 VFS 協同工作。為了能夠支持各種實際文件系統,VFS 定義了所有文件系統都支持的基本的、概念上的接口和數據 結構;同時實際文件系統也提供 VFS 所期望的抽象接口和數據結構,將自身的諸如文件、目錄等概念在形式 上與VFS的定義保持一致。換句話說,一個實際的文件系統想要被 Linux 支持,就必須提供一個符合VFS標准 的接口,才能與 VFS 協同工作。實際文件系統在統一的接口和數據結構下隱藏了具體的實現細節,所以在VFS 層和內核的其他部分看來,所有文件系統都是相同的。
5、利用C庫函數fopen(), fread(), fwrite(), fclose() 來實現簡單的文件備份, 即將一個文件的內容拷貝到另一個文件中去。
四、實驗中用到的系統調用函數(包括實驗原理中介紹的和自己采用的),自己采用的系統調用函數要按照指導書中的格式說明進行介紹。
1. open()函數
功能描述:用於打開或創建文件,在打開或創建文件時可以指定文件的屬性及用戶的權限等各種參數。
所需頭文件:#include <sys/types.h>,#include <sys/stat.h>,#include <fcntl.h>
函數原型:int open(const char *pathname,int flags,int perms)
參數:
pathname:被打開的文件名(可包括路徑名如"dev/ttyS0")
flags:文件打開方式,
O_RDONLY:以只讀方式打開文件
O_WRONLY:以只寫方式打開文件
O_RDWR:以讀寫方式打開文件
O_CREAT:如果改文件不存在,就創建一個新的文件,並用第三個參數為其設置權限
O_EXCL:如果使用O_CREAT時文件存在,則返回錯誤消息。這一參數可測試文件是否存在。此時open是原子操作,防止多個進程同時創建同一個文件
O_NOCTTY:使用本參數時,若文件為終端,那么該終端不會成為調用open()的那個進程的控制終端
O_TRUNC:若文件已經存在,那么會刪除文件中的全部原有數據,並且設置文件大小為0
O_APPEND:以添加方式打開文件,在打開文件的同時,文件指針指向文件的末尾,即將寫入的數據添加到文件的末尾
O_NONBLOCK: 如果pathname指的是一個FIFO、一個塊特殊文件或一個字符特殊文件,則此選擇項為此文件的本次打開操作和后續的I/O操作設置非阻塞方式。
O_SYNC:使每次write都等到物理I/O操作完成。
O_RSYNC:read 等待所有寫入同一區域的寫操作完成后再進行
在open()函數中,falgs參數可以通過“|”組合構成,但前3個標准常量(O_RDONLY,O_WRONLY,和O_RDWR)不能互相組合。
perms:被打開文件的存取權限,可以用兩種方法表示,可以用一組宏定義:S_I(R/W/X)(USR/GRP/OTH),其中R/W/X表示讀寫執行權限,
USR/GRP/OTH分別表示文件的所有者/文件所屬組/其他用戶,如S_IRUUR|S_IWUUR|S_IXUUR,(-rex------),也可用八進制800表示同樣的權限
返回值:
成功:返回文件描述符
失敗:返回-1
2. close()函數
功能描述:用於關閉一個被打開的的文件
所需頭文件: #include <unistd.h>
函數原型:int close(int fd)
參數:fd文件描述符
函數返回值:0成功,-1出錯
3. read()函數
功能描述: 從文件讀取數據。
所需頭文件: #include <unistd.h>
函數原型:ssize_t read(int fd, void *buf, size_t count);
參數:
fd: 將要讀取數據的文件描述詞。
buf:指緩沖區,即讀取的數據會被放到這個緩沖區中去。
count: 表示調用一次read操作,應該讀多少數量的字符。
返回值:返回所讀取的字節數;0(讀到EOF);-1(出錯)。
4. write()函數
功能描述: 向文件寫入數據。
所需頭文件: #include <unistd.h>
函數原型:ssize_t write(int fd, void *buf, size_t count);
返回值:寫入文件的字節數(成功);-1(出錯)
功能:write 函數向 filedes 中寫入 count 字節數據,數據來源為 buf 。返回值一般總是等於 count,否則就是出錯了。常見的出錯原因是磁盤空間滿了或者超過了文件大小限制。
對於普通文件,寫操作始於 cfo 。如果打開文件時使用了 O_APPEND,則每次寫操作都將數據寫入文件末尾。成功寫入后,cfo 增加,增量為實際寫入的字節數。
五、實驗步驟
1、閱讀實驗原理,認真學習關於根目錄下的文件和功能。
2、使用C庫函數實現備份文件:
(1)使用fopen()函數以只讀方式打開想要備份的源文件source和以只寫方式打開想要寫入內容的目標文件target。
(2)使用fread()循環讀取源文件一個緩沖區大小的內容,使用fwrite()將內容寫入目標文件。
(3)讀取與寫入完畢,使用fclose()關閉讀寫文件流。
3、使用系統調用函數實現備份文件:
(1)使用open()系統調用函數以只讀方式打開想要備份的源文件source和以只寫方式打開想要寫入內容的目標文件target。
(2)使用read()循環讀取源文件一個緩沖區大小的內容,使用write()將內容寫入目標文件。
(3)讀取與寫入完畢,使用close()關閉讀寫文件流。
六、實驗結果分析(截屏的實驗結果,與實驗結果對應的實驗分析)
使用c庫函數實現備份文件:
初始文件source.dat:
target.dat:
編譯並執行程序:
檢查target.dat文件:
備份文件成功!
使用系統調用函數實現備份文件的效果如出一轍,在此就不附上圖。
六、思考題
1、使用系統調用函數open(),read(),write(),close()實現簡單文件備份的原理是什么?
系統調用是操作系統的一個接口,通過調用函數在內核地址空間執行,屏蔽了對硬件資源的操作細節。
open():
1)根據給定的文件名查找文件目錄。如果找到該文件,則把相應的文件控制塊調入內存的活動文件控制塊區。
2)檢測打開文件的合法性。如果用戶指定的打開文件之后的操作與文件創建時規定的存取權限不符,則不能打開該文件,返回不成功標志。如果權限相符,則建立文件系統內部控制結構之間的通路聯系,返回相應的文件描述字fd。
read():
1)根據打開文件時得到的文件描述字找到相應的文件控制塊,確定讀操作的合法性,設置工作單源初值。
2)把文件的邏輯塊號轉換為物理塊號,申請緩沖區。
3)啟動磁盤I/O操作,把盤塊中的信息讀入緩沖區,然后傳送到指定的內存區,同時修改讀指針,供后面讀寫定位之用。
Write():
1)根據文件描述字找到文件控制塊,確認寫操作的合法性,置工作單元初值。
2)由當前寫指針的值得到邏輯塊號,然后申請空閑物理盤塊,申請緩沖區。
3)把指定用戶內存區中的信息寫入緩沖區,然后啟動磁盤進行I/O操作,將緩沖區中信息寫到相應盤上。
4)修改寫指針的值。
Close():
如果該文件的最后一塊尚未寫到盤上,則強行寫盤,不管該塊是否為滿塊。系統根據文件描述字依次找到相應的內部控制結構,切斷彼此間聯系,釋放相應的控制表格。
2、使用C庫函數fopen(), fread(), fwrite(), fclose() 來實現簡單文件備份的原理是什么?
使用C庫函數fopen()建立文件數據流,返回一個FILE結構指針,fread(),fwrite()運用FILE指針對文件流進行操作,fclose()關閉剛才建立的流。使用C庫函數實現文件備份實際上是建立兩個文件流,先讀取其中一個流的數據,再將讀取出來的數據寫入另一個流中。
3、上述二者的區別在哪里?
C庫調用是調用函數庫中的一個程序,在用戶態下進行,而系統調用是調用系統內核的服務,在內核模式中運行。庫函數調用與用戶程序相關聯,但系統調用是操作系統的一個進入點。實際上C庫函數調用可以理解為對系統調用的一層封裝,系統調用的目的明確,執行高效簡潔,C庫函數就是在此基礎上添加一些其他的操作,比如構造成流態等提供調用。
八、實驗數據及源代碼(學生必須提交自己設計的程序源代碼,並有注釋,源代碼電子版也一並提交),包括思考題的程序。
程序完整代碼請轉至個人GitHub倉庫(如果喜歡,麻煩點個star✨謝謝~)
結語:隨筆僅供參考,千萬不要照抄哦,我相信你可以的~!