檔案與輸入輸出

檔案偏移量與 lseek

/ lseek -> EL-seek /

想像用一個書籤讀一本厚書。每讀一頁,書籤就往前移;你不會每次都從第一頁重新開始。一個檔案每次開啟正好有這麼一個書籤:檔案偏移量,一個說明下一次讀或寫會發生在距開頭幾個位元組處的數字。

具體來說,檔案偏移量是從檔案開頭算起的位元組計數,存在你的描述符所指向的開啟檔案結構裡。開啟時它從 0 開始(除非你用了 O_APPEND)。每次 read(fd, buf, n) 搬了 k 個位元組,就把偏移量往前推進 k;每次 write 也一樣。所以連續呼叫三次 read,自然就會在檔案中往前走——不需額外力氣。當你想跳躍而非爬行時,lseek(fd, offset, whence) 會明確地移動書籤:whence 為 SEEK_SET(offset 從開頭算起)、SEEK_CUR(相對於目前位置,可為負)或 SEEK_END(相對於結尾)。lseek(fd, 0, SEEK_CUR) 是個方便的小技巧,用來在不移動的情況下問「我現在在哪?」。定位到檔案結尾之後再寫入,會造成一個「洞」(稀疏檔案),那段空隙讀回來都是零位元組。

為何重要:偏移量正是循序讀取「就是會動」的原因,也是隨機存取得以可能的根本。它還解釋了一個微妙處:因為偏移量住在共享的開啟檔案結構裡,由 dup() 產生的兩個描述符共用一個偏移量(透過其一讀取會同時移動兩者),而對同一檔案各自呼叫兩次 open() 則得到各自的偏移量。管線、終端機與通訊端不可定位——對它們呼叫 lseek() 會以 ESPIPE 失敗,因為沒有固定位置可以定位。

off_t pos = lseek(fd, 0, SEEK_CUR); /* 我現在在哪? */ lseek(fd, 0, SEEK_SET); /* 倒回開頭 */ lseek(fd, -4, SEEK_END); /* 結尾前 4 個位元組 */

lseek 明確地移動書籤;讀取與寫入則隱含地移動它。

偏移量屬於開啟檔案描述,而非描述符本身,所以 dup 出來的描述符共用它,但各自的 open() 呼叫不共用。lseek 不讀也不寫任何資料——它只是重新定位書籤。

又称
file positionread/write cursor讀寫游標檔案位置