C語言手冊-read

名稱:

pread,read-從文件讀

語法:

#include <unistd.h>

ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset);
ssize_t read(int fildes, void *buf, size_t nbyte);

描述:

read()函數會嘗試從fildes指定的文件描述符對應的文件中讀取nbyte個字節,然後存放到buf中。同時對相同的管道、命名管道或終端設備的多個讀取操作是未指定的

在下面描述的操作被執行之前,如果nbyte爲0,read()函數會按照下面描述的方式檢查並返回錯誤。如果沒有錯誤,或者錯誤檢測沒有執行,read()會返回0沒有進一步的結果

對於支持seek的文件(比如一個正常的文件),read()會從fildes中指定的偏移位置開始讀取。偏移量會隨着讀取的字節數增長

對於不支持seek的文件(比如終端),始終從當前位置開始讀。此種類型文件的偏移位置是未定義的

在當前文件結束位置之後不會進行任何數據的傳輸。如果起始位置在EOF及其之後都會導致read()函數返回0。如果文件是特殊設備文件,read()請求的結果是根據具體實現定義的

如果nbyte的值大於SSIZE_MAX,結果是根據定義實現的

當嘗試從空管道或者空FIFO讀取時:

  • 如果沒有進程持有管道的寫端,read()將返回0來指示EOF
  • 如果有進程持有寫端,且O_NONBLOCK被置位,read()會返回-1並將errno設置爲EAGAIN
  • 如果有進程持有寫端,且O_NONBLOCK未被置位,read()會阻塞調用線程直到有數據被寫入管道或者所有持有寫端的進程被關閉

當嘗試從一個支持非阻塞讀的文件(非管道/匿名管道)讀取,且當前沒有數據可用時:

  • 如果O_NONBLOCK被置位,read()函數會返回-1並將errno設置爲EAGAIN
  • 如果O_NONBLOCK沒有置位,read()會阻塞調用線程直到有數據可用
  • O_NONBLOCK標誌位的使用不會在有數據可用的時候產生影響

read()函數會從文件中讀取之前寫過的數據。如果文件EOF之前的數據還沒有被寫入,read()仍會返回數據但內容爲0。例如,lseek()函數允許將偏移設置在當前已有數據之後的位置,隨後就可以在這裏寫數據,在這兩片數據之間的read()操作就會返回內容爲0的數據

在函數成功執行之後,此時nbyte>0,read()會更新相關文件的最後數據獲取時間戳,然後返回成功讀取的字節數。返回的數字不會大於nbyte。返回值會在文件中剩餘的字節少於nbyte個時小於nbyte,這種情況可能發生於read()請求被信號量打斷、文件是管道/命名管道或者其他特殊文件在讀取的時候立即可用的數據少於nbyte。比如,從和終端相關聯的文件讀取的數據可能就是一行字符

如果read()函數在讀取任何數據之前被信號量打斷,會返回-1並將errno設置爲EINTR

如果read()函數在讀取了一些數據之後被信號量打斷,會返回成功讀取的字節數

對於通常的文件,超過fildes指向的文件描述指定的最大偏移值的數據不會進行傳輸

如果fildes引用了socket,read()函數和沒有設置flag的recv()相同

如果O_DSYNC和O_RSYNC被置位,在文件描述符上的讀I/O操作將會按照同步I/O數據完整性的定義來完成;如果O_SYNC和O_RSYNC被置位,在文件描述符上的讀I/O操作將會按照同步I/O文件完整性的定義來完成

如果fildes指向的是一個共享內存對象,讀操作的結果將是未定義的

如果fildes指向的是一個類型內存對象,讀操作的結果將是未定義的

從流文件讀取的read()函數可以以三種模式讀取數據:比特流模式、消息不保留模式、消息捨棄模式。默認是比特流模式。模式可以使用I_SRDOPT ioctl()請求修改,可以用I_GRDOPT ioctl()請求檢測。比特流模式下,read()會盡可能多的從流中讀取數據直到滿足請求的數量或者流中沒有數據,而忽視消息邊界

在消息保留模式下,read()會盡可能多的讀取數據直到滿足請求或者達到消息邊界。如果read()沒有讀取消息中所有的數據,剩下的數據仍會留在流中等待下一次讀取。相反的,消息捨棄模式下,read()讀取後消息中剩下的數據會被捨棄,後續如果有read()、getmsg()、getpmsg()也將無法讀取到

read()處理0字節流的方式取決於當前的讀取模式。字節流模式下,read()會持續讀取數據直到滿足nbyte個或者沒有更多的數據或者遇到0字節消息阻塞。read()函數之後返回成功讀取的字節數,並將0字節消息放回流中以待下一個read()、getmsg()、getpmsg()讀取。在消息保留或消息捨棄模式下,遇到0字節消息之後將會返回0並將其從流中移除。如果0字節消息是流中讀取的第一個消息,無論處於何種模式這個消息都會被捨棄並返回0

read()從流中讀取數據的時候會返回流的頭讀取隊列的最前面的消息,無論消息的優先級是什麼

默認情況下,流是控制正常模式,在這種模式下read()只能從生成的消息中只包含數據而不包含控制部分的流文件。如果消息中包含了控制部分,read()就會失敗。可以通過I_SRDOPT ioctl()命令改變默認的流模式爲控制數據模式或者控制捨棄模式。在控制數據模式下,read()會將所有的控制部分轉化爲數據並在發送任何原生的數據部分之前將其發送。在控制捨棄模式下,read()會捨棄所有的控制部分

此外,如果在read()調用之前流的頭就已經處理過一個異步錯誤,read()會失敗。在這種情況下errno將不會反應read()的結果,而是反應之前的錯誤。如果read()讀取的流出現了暫停,read()仍會繼續執行直到流的頭讀取隊列爲空,然後返回0

pread()函數和read()函數基本一致,除了pread()會從給定的偏移位置讀取而且不會改變偏移位置。pread()的第四個參數指定了偏移。如果指定了無法seek到的位置,蔣會導致錯誤

返回值:

在成功執行的情況下,這些函數會返回一個非負整數指明成功讀取的字節數。否則函數會返回-1並設置errno指明錯誤

錯誤:

在下列情況下函數執行會失敗:

EAGAIN:文件不是管道、命名管道、socket,文件描述符的O_NONBLOCK標誌位被置位,讀操作將會阻塞進程。

EBADF:fildes不是一個可用於打開並讀取的文件描述符

EBADMSG:文件是流文件,而且待讀取的消息中包含控制部分

EINTR:讀操作被信號量中斷,而且沒有數據被傳輸

EINVAL:fildes指定的文件過着多路選擇器是另一個多路選擇器的下游

EIO:後臺進程組的一個進程成員嘗試從它的控制終端讀取數據,而且調用線程關閉了SIGTTIN或者進程忽視了SIGTTIN或者進程所屬的進程組是孤兒進程組。這個錯誤也可能因爲具體實現定義的原因出現

EISDIR:fildes指向了一個目錄,但是具體實現不允許read()或pread()讀取目錄。應該使用readdir()函數

EOVERFLOW:文件是正常文件,nbyte大於0,起始位置在EOF之前,但是起始位置大於或等於fildes指向的文件描述中指定的最大偏移值

pread()函數在下列情況下會失敗:

EINVAL:指定的偏移量是負數,文件的偏移量將維持不變

ESPIPE:文件不支持seek

read()函數在下列情況下會失敗:

EAGAIN:文件是管道或者命名管道,O_NONBLOCK標誌位被置位,但是線程會被讀操作阻塞

EAGAIN或EWOULDBLOCK:文件時socket,O_NONBLOCK被置位,但是線程會被讀操作阻塞

ECONNRESET:嘗試從一個被其上級強制關閉的socket讀

ETIMEDOUT:嘗試從socket中讀的時候出現了超時

函數可能會在下列情況下失敗:

EIO:物理I/O錯誤

ENOBUFS:系統資源不足以執行操作

ENOMEM:內存不足以支持操作

ENXIO:請求中含有不存在的設備,或者請求超出了設備的能力

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章