天天看點

《Linux系統程式設計(第2版)》——2.7 用lseek()查找

本節書摘來自異步社群《linux系統程式設計(第2版)》一書中的第2章,第2.7節,作者:【美】robert love著,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視

一般情況下,i/o是線性的,由于讀寫引發的隐式檔案位置更新都需要seek操作。但是,某些應用要跳躍式讀取檔案,需要随機通路而不是線性通路。lseek()系統調用能夠将檔案描述符的位置指針設定成指定值。lseek()隻更新檔案位置,沒有執行其他操作,也并不初始化任何i/o:

《Linux系統程式設計(第2版)》——2.7 用lseek()查找

lseek()調用的行為依賴于origin參數,該參數可以是以下任意值之一:

seek_cur

将檔案位置設定成目前值再加上pos個偏移值,pos可以是負值、0或正值。如果pos值為0,傳回目前檔案位置值。

seek_end

将檔案位置設定成檔案長度再加上pos個偏移值,pos可以是負值、0或正值。如果pos值為0,就設定成檔案末尾。

seek_set

将檔案位置設定成pos值。如果pos值為0,就設定成檔案開始。

調用成功時傳回新的檔案位置,錯誤時傳回-1,并相應設定errno值。

舉個例子,以下代碼把fd的檔案位置指針設定為1825:

《Linux系統程式設計(第2版)》——2.7 用lseek()查找

下面是把fd的檔案位置設定成檔案末尾:

《Linux系統程式設計(第2版)》——2.7 用lseek()查找

由于lseek()傳回更新後的檔案位置,可以通過seek_cur,把偏移pos設定成0,确定目前檔案位置:

《Linux系統程式設計(第2版)》——2.7 用lseek()查找

到目前為止,lseek()調用最常見的用法是将指針定位到檔案的開始、末尾或确定檔案描述符的目前檔案位置。

2.7.1 在檔案末尾後查找

lseek()支援在檔案末尾之後進行查找。例如,以下代碼會定位到fd指向檔案末尾之後的1688位元組。

《Linux系統程式設計(第2版)》——2.7 用lseek()查找

對這種用法本身而言,查找到檔案末尾之後沒什麼意義——對該新的檔案位置的讀請求會傳回eof。但是,如果在該位置有個寫請求,在檔案的舊長度和新長度之間的空間會用0來填充。

這種零填充區間稱為“空洞(hole)”。在unix系檔案系統上,空洞不占用任何實體磁盤空間。這意味着檔案系統上所有檔案的大小加起來可以超過磁盤的實體大小。包含空洞的檔案稱為“稀疏檔案(sparse file)”。稀疏檔案可以節省很多空間,并提升性能,因為操作空洞不會産生任何實體i/o。

對檔案空洞部分的讀請求會傳回相應的二進制0。

2.7.2 錯誤碼

lseek()調用出錯時,傳回-1,并将errno值設定成如下四個值之一:

ebadf

給定的檔案描述符沒有指向任何打開的檔案描述符。

einval

origin的值不是設定成seek_set、seek_cur或seek_end,或者結果檔案位置是負值。對于einval,如果同時出現以上兩種錯誤就太糟了。前者幾乎可以肯定是個編譯時錯誤,後者則是不太明顯的運作時邏輯錯誤。

eoverflow

結果檔案偏移不能通過off_t表示。隻有在32位的體系結構上才會發生這種錯誤。目前檔案位置已經更新,該錯誤表示無法傳回更新的值。

espipe

給出的檔案描述符和不支援查找操作的對象關聯,比如管道、fifo或socket。

2.7.3 限制

最大檔案位置是受限于off_t類型的大小。大部分計算機體系結構定義該值為c long類型,在linux上是指字長(word size)(即計算機的通用寄存器大小)。但是,核心在内部實作上是把偏移存儲成c long long類型。這對于64位計算機沒有什麼問題,但是對于32位計算機,當執行查找操作時,可能會産生溢出eoverflow的錯誤。

繼續閱讀