文件 I/O API 簡要介紹:read, pread 和 readv, preadv

在 linux 平臺,如果想從文件描述符中讀取數據,主要通過以下 API 實現,當然還有其他 API。

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

ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
ssize_t preadv(int fd, const struct iovec *iov, int iovcnt,  off_t offset);

read 會從 fd 當前的 offset 處開始讀,讀取完 nbyte 後,該 fd 的 offset 會增加 nbyte(假設可以讀取到 nbyte),下一次 read 則從新的 offset 處開始讀。

而 pread 則是從指定的 offset 處開始讀,這個 offset 是相對於 0 的一個絕對值,與 fd 當前的 offset 沒有關係。

打開一個文件時,offset 默認爲 0;如果打開時指定了 O_APPEND 選項,那麼 offset 爲 SEEK_END 即文件末尾。

read 和 pread 的區別就是,read 會改變 fd 的 offset,而 pread 不會改變。

pread 的實際操作類似於 lseek + read,即先將 offset 調整到指定值,再調用 read 讀取數據,兩者的區別在於 pread 是一個原子操作,從而可以保證一定是從指定的 offset 處開始讀;另外就是 pread 讀取完數據會恢復執行之前的 offset,即 pread 操作前後的 offset 是一致的。

readv 則是從 fd 中讀取數據到多個 buf,buf 數爲 iovcnt,每個 buf 有自己的長度(可以一樣),一個 buf 寫滿(寫指讀出數據並保存),才接着寫下一個 buf,依次類推。preadv 與 readv 的關係,與上述 read 和 pread 的關係一樣。

除了文件 I/O,還有網絡 I/O,read/write 也可用於網絡 I/O,只用於網絡 I/O 的 API 有:

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
               const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
              struct sockaddr *src_addr, socklen_t *addrlen);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

read、write 和 recv、send 在網絡 I/O 上並無本質區別,只是在參數上面有細微差別。

接下來的問題是,各個 API 的使用場景,後續完善。

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