c語言文件IO庫函數——APUE學習筆記(1)

大多數函數只需要五個函數實現IO操作:open, read, write, lseek, close.


一. 文件描述符:

文件描述符時一個非負整數(0~OPEN_MAX - 1).當打開現有文件或者創建新文件時,內核向進程返回一個文件描述符一邊標示一個文件。
內核文件描述符要區別於shell文件描述符:shell內定了幻數0, 1, 2分別表示標準輸入,標準輸出和標準錯誤。

二. 文件操作函數:


1.open或openat:


(1). 打開文件,成功返回文件描述符,失敗返回-1.

#include <fcntl.h>

int open(const char *path, int oflag, ... /*mode_t mode */);
int openat(int fd, const char *path, int oflag, ... /*mode_t mode */);

(2). 參數:

a. path表示文件路徑;
b. oflag用來說明該函數的多個選項,如:O_RDONLY, O_WRONLY, O_RDWR分別表示只讀,只寫和可讀寫,而O_CREAT選項表示當打開文件不存在時創建這個文件,O_DIRECTORY選項表示如果path應用的不是目錄則出錯。這些選項都可以通過man page查詢獲得。
c. …參數:ISO C用這種方法表示剩餘參數爲可變參數,即在需要時可以變參。

(3). 文件描述符fd參數將open和openat區分開來:

a. 當path指定的爲絕對路徑時,fd參數被忽略,兩函數相等。
b. 怕path指出相對路徑名時,fd參數相對路徑名在文件系統中的開始地址。fd參數是通過打開相對路徑名所在的目錄來獲取的。
c. path參數指定了相對路徑名,fd參數具有特殊值AT_FDCWD。在這種情況下路徑名在當前工作目錄中獲取,openat和open類似。

2.creat


(1). 創建只寫文件,成功返回只寫文件描述符,失敗返回-1.


#include <fcntl.h>

int creat(const char *path, mode_t mode);

此函數等效於:

open(path, O_RDWR|O_CREAT|O_TRUNC, mode);

(2). 參數:

a. path爲路徑
b. mode爲權限模式

(3). creat函數只能以只寫方式打開所創建的文件。早期版本中使用該函數,現在多用open函數代替

open(path, O_RDWR|O_CREAT|O_TRUNC, mode);

3.close

(1). 關閉文件,成功返回0,出錯返回-1.

#include <unistd.h>

int close(int fd);

(2). 當文件關閉同時會釋放所有加在該文件上的記錄鎖。

(3). 當一個文件終止時,內核會自動關閉它所打開的所有文件。所以close函數一般不現式使用。

4.lseek

(0). 文件偏移量:通常是一個非負整數,用以度量從文件開始處計算的字節數。

#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);

(1). 設置文件偏移量,成功返回返回新的文件偏移量,失敗返回-1.

(2). 參數:

a. offset參數解釋和whence值有關:
-> whence爲SEEK_SET時,文件偏移量將被設爲距文件開始offset個字節。
-> whence爲SEEK_CUR時,文件偏移量將被設爲當前偏移量加上offset(offset正負都可)。
-> whence爲SEEK_END時,文件偏移量將被設爲文件長度加offset(offset正負都可)。

(3). 管道,FIFO, 網絡套接字不可設置偏移量,若對其操作,返回-1,errno爲ESPIPE。

(4). 一般情況文件的偏移量爲一個非負整數,但是某些特殊設備時允許負的偏移量的,so~,判斷文件偏移量是否設置成功應該看看他的lseek返回值是否爲-1,而不是判斷它是不是負數。

(5). lseek僅僅時將文件偏移量記錄在內核中,他本身並不引起IO操作,這個偏移量的存在只是給下一次的讀和寫操作的。

(6). 文件空洞:文件偏移量時可以大於文件當前長度的,這樣如果得到偏移量後的執行一次寫操作,寫的位置和文件開頭就存在了一片空白區,這段區域被字符0填滿,稱之爲空洞,(空洞不要求佔用磁盤存儲區)。

5.read

(1). 讀文件,返回讀到的字節數,弱國已經讀到文件末尾了,則返回0,失敗返回-1。

#include <unisted.h>

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

(2). 在下述情況下,函數實際讀到的字節數少於要求讀到的字節數。

a. 要求讀的大小大於文件本身大小時:
在還沒讀到文件要求大小時文件已經讀到末尾了.例如:如文件只有30字節,而要求 讀100字節,這樣read函數將返回30,下次調用read時它將返回0.

b. 從終端讀設備讀時:
一次只讀一行,和標準輸出按行刷新對應.

c. 從網絡讀數據時:
網絡緩存機制導致返回值小於要求讀的大小.

d.從管道讀取數據時:
返回實際管道可用數據.

e. 從面向記錄設備讀時:
一次只能讀一條記錄.

f. 讀過程中遇到信號中斷時:
返回實際讀到的數據.

g. 返回值類型(ssize_t)爲帶符號整數:
爲確保函數可以返回正整數字節,0(到文件尾),-1(出錯).

6.函數write.

(1). 寫入函數,向文件描述符爲fd的已打開文件中寫數據,成功返回寫入字節數,出錯返回-1.

(2). write函數的返回值通常與nbytes值相同,否則表示出錯.

(3). 出錯原因常見爲:

a.磁盤已滿.
b.超過給定進程的文件長度限制.

(4).普通文件執行寫使用write時,寫操作是從文件當前偏移量處開始.

在文件打開時設置追加屬性O_APPEND,這樣在每次寫操作時文件偏移量就會被設置在文件末尾處,寫成功後,文件偏移量增加寫入文件長度.

例:用read和write函數實現簡單函數複製:

#include <apue.h> //apue.h頭文件中包含有write,read以及基本操作頭文件

#define BUFFSIZE 4096

int main(int argc, char **argv)
{
    int n;
    char buf[BUFFSIZE];

    //從標準輸入讀文件,每次讀BUFFSIZE個字節,讀到buf數組中
    while((n == read(STDIN_FILENO, buf, BUFFSIZE)) > 0){
        //read正確時,寫入文件到標準輸出中,一次寫n個字節
        if(write(STDOUT_FILENO, buf, n) != n){
            err_sys("write error!");
        }
    }

    //read函數返回-1時,輸出錯誤信息並退出
    if(n < 0){
        err_sys("read error!");
    }

    exit(0);
}
發佈了32 篇原創文章 · 獲贊 10 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章