內核使用三種數據結構表示打開的文件,分別是文件描述符表、文件表和 V 節點表。它們之間的關系決定了在文件共享方面一個進程對另一個進程可能產生的影響。
- 每個進程在進程表中都有一個記錄項,記錄項中包含有一張打開文件描述符表,每個描述符占用一項。與每個文件描述符相關聯的是:
(a) 文件描述符標志。
(b) 指向一個文件表項的指針。
- 內核為所有打開文件維持一張文件表。每個文件表項包含:
(a) 文件狀態標志(讀、寫、添寫、同步和非阻塞等)。
(b) 當前文件偏移量。
(c) 指向該文件 V 節點表項的指針。
- 每個打開文件(或設備)都有一個 v 節點(v-node)結構。v 節點包含了文件類型和對此文件進行各種操作的函數的指針。v 節點還包含了從磁盤讀取的 i 節點(i-node)的信息,i 節點信息包含了文件的所有者、文件長度、文件所在的設備、指向文件的實際數據塊在磁盤上的所在位置的指針等。
圖 1 顯示了一個進程的三張表之間的關系。該進程有兩個不同的打開文件,一個文件打開為標准輸入(文件描述符為 0),另一個打開為標准輸出(文件描述符為 1)。
圖 1: 一個進程打開兩個文件的內核數據結構
圖 2 給出了兩個進程打開同一個文件的內核數據結構。假定第一個進程在文件描述符 3 上打開該文件,而另一個進程在文件描述符 4 上打開該文件。打開該文件的每個進程都得到一個文件表項,但對一個給定的文件只有一個 v 節點表項。
圖 2: 兩個進程打開同一個文件的內核數據結構
有了這些數據結構,對一些概念和操作有以下說明:
- 每個進程都會獲得自己的文件表項,因此,每個進程都有它自己的對該文件的當前偏移量。
- 在完成每個 write 後,在文件表項中的當前文件偏移量即增加所寫入的字節數。如果這導致當前文件偏移量超出了當前文件長度,則將 i 節點表項中的當前文件長度設置為當前文件偏移量(也就是該文件加長了)。
- 如果用O_APPEND 標志打開一個文件,則相應標志也被設置到文件表項的文件狀態標志中。每次對這種具有追加寫標志的文件執行寫操作時,文件表項中的當前文件偏移量首先會被設置為 i 節點表項中的文件長度。這就使得每次寫入的數據都追加到文件的當前尾端處。
- 若一個文件用 lseek 定位到文件當前的尾端,則文件表項中的當前文件偏移量被設置為 i 節點表項中的當前文件長度。可知,這與上述用O_APPEND 標志打開文件的方式是不同的。
- lseek 函數只修改文件表項中的當前文件偏移量,不進行任何的 I/O 操作。
Linux ---lseek() 函數 http://www.linuxidc.com/Linux/2015-01/111699.htm