天天看點

linux C程式設計-标準I/O1、标準 I/O 和檔案 I/O 的差別2、标準輸入、标準輸出和标準錯誤3、fopen()函數4、fclose()函數 5、fread()函數6、fwrite()函數7、fseek()函數8、ftell()函數9、feof()函數10、ferror()函數11、clearerr()函數12、stdio緩沖區12.1、setvbuf()函數13、檔案描述符與 FILE 指針互轉

目錄

1、标準 I/O 和檔案 I/O 的差別

2、标準輸入、标準輸出和标準錯誤

3、fopen()函數

4、fclose()函數

5、fread()函數

6、fwrite()函數

7、fseek()函數

8、ftell()函數

9、feof()函數

10、ferror()函數

11、clearerr()函數

12、stdio緩沖區

12.1、setvbuf()函數

12.2、setbuf()函數

12.3、setbuffer()函數

12.4、fflush()函數

12.5、重新整理 stdio 緩沖區

13、檔案描述符與 FILE 指針互轉

13.1、fileno()函數

13.2、fdopen()函數

1、标準 I/O 和檔案 I/O 的差別

1) 标準 I/O 是标準 C 庫函數,而檔案 I/O 則是 Linux系統調用;

2) 标準 I/O 是由檔案 I/O 封裝而來,标準 I/O 内部實際上是調用檔案 I/O 來完成實際操作的;

3) 可移植性:标準 I/O 相比于檔案 I/O 具有更好的可移植性,通常對于不同的作業系統,其核心向應用層提供的系統調用往往都是不同;而對于标準 I/O 來說,由于很多作業系統都實作了标準 I/O 庫,标準 I/O 庫在不同的作業系統之間其接口定義幾乎是一樣的,是以标準 I/O 在不同作業系統之間相比于檔案 I/O 具有更好的可移植性。

4)性能: 标準 I/O 庫在使用者空間維護了自己的 stdio 緩沖區, 是以标準 I/O 是帶有緩存的,而檔案 I/O 在使用者空間是不帶有緩存的,是以在性能、效率上,标準 I/O 要優于檔案 I/O。

2、标準輸入、标準輸出和标準錯誤

檔案 I/O 中,可以使用 STDIN_FILENO、 STDOUT_FILENO、 STDERR_FILENO來表示标準輸入、标準輸出和标準錯誤。

#include <unistd.h>

/* Standard file descriptors. */
#define STDIN_FILENO 0 /* Standard input. */
#define STDOUT_FILENO1 /* Standard output. */
#define STDERR_FILENO2 /* Standard error output. */
           

标準 I/O 中,可以使用 stdin、 stdout、 stderr 來表示标準輸入、标準輸出和标準錯誤。

#include <stdio.h>

/* Standard streams. */
extern struct _IO_FILE *stdin; /* Standard input stream. */
extern struct _IO_FILE *stdout; /* Standard output stream. */
extern struct _IO_FILE *stderr; /* Standard error output stream. */
/* C89/C99 say they're macros. Make them happy. */
#define stdin stdin
#define stdout stdout
#define stderr stderr
           

3、fopen()函數

打開或建立檔案。

#include <stdio.h>
FILE *fopen(const char *path, const char *mode);
           

參數 path: 參數 path 指向檔案路徑,可以是絕對路徑、也可以是相對路徑。

參數 mode: 參數 mode 指定了對該檔案的讀寫權限,是一個字元串。

mode 說明 對應于 open()函數的 flags 參數取值
r 以隻讀方式打開檔案 O_RDONLY
r+ 以可讀、可寫方式打開檔案 O_RDWR
w 以隻寫方式打開檔案,如果參數 path 指定的檔案存在,将檔案長度截斷為 0;如果指定檔案不存在則建立該檔案 O_WRONLY | O_CREAT | O_TRUNC
w+ 以可讀、可寫方式打開檔案,如果參數 path 指定的檔案存在,将檔案長度截斷為 0;如果指定檔案不存在則建立該檔案。 O_RDWR | O_CREAT | O_TRUNC
a 以隻寫方式打開檔案,打開以進行追加内容(在檔案末尾寫入),如果檔案不存在則建立該檔案。 O_WRONLY | O_CREAT | O_APPEND
a+ 以可讀、可寫方式打開檔案,以追加方式寫入(在檔案末尾寫入),如果檔案不存在則建立該檔案。 O_RDWR | O_CREAT | O_APPEND

傳回值: 調用成功傳回一個指向 FILE 類型對象的指針(FILE *),該指針與打開或建立的檔案相關聯,後續的标準 I/O 操作将圍繞 FILE 指針進行。 如果失敗則傳回 NULL,并設定 errno 以訓示錯誤原因。

注:調用 fopen()函數建立檔案時無法手動指定檔案的權限,但卻有一個預設值:

S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH (0666)
           

4、fclose()函數

關閉一個由 fopen()打開的檔案。

#include <stdio.h>
int fclose(FILE *stream);
           

參數 stream :為 FILE 類型指針,

傳回值 :調用成功傳回 0;失敗将傳回 EOF(也就是-1),并且會設定 errno 來訓示錯誤原因。

5、fread()函數

對檔案進行讀操作。

#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
           

參數 ptr: 将讀取到的資料存放在參數 ptr 指向的緩沖區中;

參數 size:從檔案讀取 nmemb 個資料項,每一個資料項的大小為 size 個位元組,是以總共讀取的資料大小為 nmemb * size 個位元組。

參數 nmemb: 參數 nmemb 指定了讀取資料項的個數。

參數 stream: FILE 指針。

傳回值: 調用成功時傳回讀取到的資料項的數目;如果發生錯誤或到達檔案末尾,則 fread()傳回的值将小于參數 nmemb。

注:fread()傳回值不能區分檔案結尾和錯誤, 究竟是哪一種情況,此時可以使用 ferror()或 feof()函數來判斷。

6、fwrite()函數

對檔案進行寫操作。

#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
           

參數 ptr: 将參數 ptr 指向的緩沖區中的資料寫入到檔案中。

參數 size: 參數 size 指定了每個資料項的位元組大小。

參數 nmemb: 參數 nmemb 指定了寫入的資料項個數。

參數 stream: FILE 指針。

傳回值: 調用成功時傳回讀取到的資料項的數目;如果發生錯誤,則 fwrite()傳回的值将小于參數 nmemb。

7、fseek()函數

設定檔案讀寫位置偏移量。

#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
           

參數 stream: FILE 指針。

參數 offset:偏移量,以位元組為機關。

參數 whence: 

SEEK_SET 讀寫偏移量将指向 offset 位元組位置處(從檔案頭部開始算)
SEEK_CUR 讀寫偏移量将指向目前位置偏移量 + offset 位元組位置處, offset 可以為正、也可以為負,如果是正數表示往後偏移,如果是負數則表示往前偏移
SEEK_END 讀寫偏移量将指向檔案末尾 + offset 位元組位置處,同樣 offset 可以為正、也可以為負,如果是正數表示往後偏移、如果是負數則表示往前偏移。

傳回值: 成功傳回 0;發生錯誤将傳回-1,并且會設定 errno 以訓示錯誤原因; 

注:傳回值成功傳回 0;發生錯誤将傳回-1!!!(與lseek的傳回值不一樣)。

8、ftell()函數

擷取檔案目前的讀寫位置偏移量。

#include <stdio.h>
long ftell(FILE *stream);
           

參數 stream: FILE 指針。

傳回值 偏移量。

注:可以通過 fseek()和 ftell()來計算出檔案的大小。

9、feof()函數

用于測試參數 stream 所指檔案的 end-of-file 标志。

#include <stdio.h>
int feof(FILE *stream);
           

參數 stream: FILE 指針。

傳回值 :如果 end-of-file 标志被設定了,則傳回一個非零值。如果 end-of-file 标志沒有被設定,則傳回 0。

10、ferror()函數

測試參數 stream 所指檔案的錯誤标志。

#include <stdio.h>
int ferror(FILE *stream);
           

參數 stream: FILE 指針。

傳回值 :如果錯誤标志被設定了,則調用 ferror()函數将傳回一個非零值,如果錯誤标志沒有被設定,則傳回 0。

11、clearerr()函數

清除 end-of-file 标志和錯誤标志,當調用 feof()或 ferror()校驗這些标志後,通常需要清除這些标志,避免下次校驗時使用到的是上一次設定的值,此時可以手動調用 clearerr()函數清除标志。

#include <stdio.h>
void clearerr(FILE *stream);
           

參數 stream: FILE 指針。

注:對于 end-of-file 标志,除了使用 clearerr()顯式清除之外,當調用 fseek()成功時也會清除檔案的 end-offile 标志。

12、stdio緩沖區

12.1、setvbuf()函數

對檔案的 stdio 緩沖區進行設定,譬如緩沖區的緩沖模式、 緩沖區的大小、起始位址等。

#include <stdio.h>
int setvbuf(FILE *stream, char *buf, int mode, size_t size);
           

參數 stream: FILE 指針,用于指定對應的檔案, 每一個檔案都可以設定它對應的 stdio 緩沖區。

參數 buf: 如果參數 buf 不為 NULL,那麼 buf 指向 size 大小的記憶體區域将作為該檔案的 stdio 緩沖區,因為stdio 庫會使用 buf 指向的緩沖區,是以應該以動态或靜态的方式在堆中為該緩沖區配置設定一塊空間,而不是配置設定在棧上的函數内的自動變量(局部變量)。如果 buf 等于 NULL,那麼 stdio 庫會自動配置設定一塊空間作為該檔案的 stdio 緩沖區(除非參數 mode 配置為非緩沖模式) 。

參數 mode: 參數 mode 用于指定緩沖區的緩沖類型,可取值如下:

_IONBF 不對 I/O 進行緩沖(标準錯誤 stderr 預設屬于這一種類型,進而保證錯誤資訊能夠立即輸出)  意味着每個标準 I/O 函數将立即調用 write()或者 read(),并且忽略 buf 和 size 參數(可以分别指定兩個參數為 NULL 和 0)。
_IOLBF 采用行緩沖 I/O(對于終端裝置預設采用的就是行緩沖模式,譬如标準輸入和标準輸出)

對于輸出流,在輸出一個換行符前将資料緩存(除非緩沖區已經被填滿), 當輸出換行符時,再将這一行資料通過檔案 I/O write()函數刷入到核心緩沖區中;

對于輸入流, 每次讀取一行資料。

_IOFBF 采用全緩沖 I/O(預設普通磁盤上的正常檔案預設常用這種緩沖模式)。

對于輸出流,當 fwrite 寫入檔案的資料填滿緩沖區時,才調用 write()将 stdio 緩沖區中的資料刷入

核心緩沖區;

對于輸入流,每次讀取 stdio 緩沖區大小個位元組資料。

size: 指定緩沖區的大小。

傳回值: 成功傳回 0,失敗将傳回一個非 0 值,并且會設定 errno 來訓示錯誤原因。

12.2、setbuf()函數

setbuf()函數建構與 setvbuf()之上,執行類似的任務。要麼将 buf 設定為 NULL 以表示無緩沖,要麼指向由調用者配置設定的 BUFSIZ 個位元組大小的緩沖區(BUFSIZ 定義于頭檔案<stdio.h>中,該值通常為 8192)

#include <stdio.h>

void setbuf(FILE *stream, char *buf);
           

setbuf()調用除了不傳回函數結果(void)外,就相當于:

setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
           

12.3、setbuffer()函數

對檔案的 stdio 緩沖區進行設定。

#include <stdio.h>

void setbuffer(FILE *stream, char *buf, size_t size);
           

setbuffer()調用除了不傳回函數結果(void)外,就相當于:

setvbuf(stream, buf, buf ? _IOFBF : _IONBF, size);
           

12.4、fflush()函數

重新整理stdio緩沖區。

#include <stdio.h>

int fflush(FILE *stream);
           

參數 stream:FILE指針對象。

傳回值:調用成功傳回 0,否則将傳回-1,并設定 errno 以訓示錯誤原因。

12.5、重新整理 stdio 緩沖區

1)調用 fflush()庫函數可強制重新整理指定檔案的 stdio 緩沖區;

2)調用 fclose()關閉檔案時會自動重新整理檔案的 stdio 緩沖區;

3)程式退出時會自動重新整理 stdio 緩沖區(注如果使用_exit 或_Exit()終止程式則不會重新整理) 。

13、檔案描述符與 FILE 指針互轉

13.1、fileno()函數

将标準 I/O 中使用的 FILE 指針轉換為檔案 I/O 中所使用的檔案描述符。

#include <stdio.h>

int fileno(FILE *stream);
           

參數 stream:要轉換的 FILE 指針

傳回值:成功傳回檔案描述符,錯誤将傳回-1,并且會設定 errno 來訓示錯誤原因。

13.2、fdopen()函數

将檔案 I/O 中所使用的檔案描述符轉換為标準 I/O 中使用的 FILE 指針。

#include <stdio.h>

FILE *fdopen(int fd, const char *mode);
           

參數 fd:要轉換的檔案描述符

參數 mode:同fopen的mode參數

傳回值:成功傳回FILE 指針,錯誤将傳回-1,并且會設定 errno 來訓示錯誤原因。

繼續閱讀