天天看點

Linux下read和write的正确用法

我寫這篇文章的目的是為了對read和write兩個函數的用法做一個總結,同時提醒自己不要忘記:

一、原型介紹

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);

參數:   

fd: 将要讀取資料的檔案描述詞。

buf:  所讀取到的資料的記憶體緩沖。 

count: 需要讀取的資料量。

read()會把參數fd所指的檔案傳送nbyte個位元組到buf指針所指的記憶體中。若參數nbyte為0,則read()不會有作用并傳回0。傳回值為實際讀取到的位元組數,如果傳回0,表示已到達檔案尾或無可讀取的資料。錯誤傳回-1,并将根據不同的錯誤原因适當的設定錯誤碼。

EAGAIN:打開檔案時設定了O_NONBLOCK标志,并且目前沒有資料可讀取

EBADF:檔案描述詞無效,或者檔案不可讀

EFAULT:參數buf指向的空間不可通路

EINTR:資料讀取前,操作被信号中斷

EINVAL:一個或者多個參數無效

EIO:讀寫出錯

EISDIR:參數fd索引的時目錄

二、read和write的正确用法

①不完善的用法一:

int ret = read(fd, buf, len);

if(ret == -1){

    exit(-1);

}else if(ret == 0){

    close(fd);

}

忽略了 errno 的處理. 仔細看文檔, 函數傳回 -1 不能完全代表 fd 錯誤, 還需要結合 errno。

②不完善用法二:

int ret = read(fd, buf, len);

if(ret == -1){

if(errno == EINTR){

// 怎麼辦?

}else if(errno == EAGAIN){

// 怎麼辦

}

exit(-1);

}else if(ret == 0){

close(fd);

}

EINTR 表示 read() 函數調用被系統中斷了, 調用者和 fd 都沒有問題, 有問題的是作業系統。而 EAGAIN 是在非阻塞 IO 時會出現. 上面的代碼判斷了 errno, 但不知道下一步該怎麼做, 還不行。

③正确用法

while(1){

    int ret = read(fd, buf, len);

    if(ret == -1){

        if(errno == EINTR){

            continue;

        }else if(errno == EAGAIN){

            // 根據你和調用者的約定, 傳回一個數值告訴它再次重試

            // 一般是結合 select/epoll 等 IO 多路複用函數

        }

        exit(-1);

    }else if(ret == 0){

        close(fd);

    }

    // proc

    break;

}

write函數也有類似用法。

繼續閱讀