C語言標準庫概覽詳述[8]-標準IO

頭文件<stdio.h>定義了用於輸入和輸出的函數、類型和宏。最重要的類型是用於聲明文件指針的FILE。另外兩個常用的類型是size_t和fpos_t,size_t是由運算符sizeof產生的無符號整類型;fpos_t類型定義能夠唯一說明文件中的每個位置的對象。由頭部定義的最有用的宏是EOF,其值代表文件的結尾。

8.1文件操作

8.1.1 fopen

FILE *fopen(const char *filename, const char *mode); 返回:成功爲FILE指針,失敗爲NULL

打開以filename所指內容爲名字的文件,返回與之關聯的流。

mode決定打開的方式,可選值如下:

"r" 打開文本文件用於讀
"w" 創建文本文件用於寫,並刪除已存在的內容(如果有的話)
"a" 添加;打開或創建文本文件用於在文件末尾寫
"rb" 打開二進制文件用於讀
"wb" 創建二進制文件用於寫,並刪除已存在的內容(如果有的話)
"ab" 添加;打開或創建二進制文件用於在文件末尾寫
"r+" 打開文本文件用於更新(即讀和寫)
"w+" 創建文本文件用於更新,並刪除已存在的內容(如果有的話)
"a+" 添加;打開或創建文本文件用於更新和在文件末尾寫
"rb+"或"r+b" 打開二進制文件用於更新(即讀和寫)
"wb+"或"w+b" 創建二進制文件用於更新,並刪除已存在的內容(如果有的話)
"ab+"或"a+b" 添加;打開或創建二進制文件用於更新和在文件末尾寫

後六種方式允許對同一文件進行讀和寫,要注意的是,在寫操作和讀操作的交替過程中,必須調用fflush()或文件定位函數如fseek()、fsetpos()、rewind()等。

文件名filename的長度最大爲FILENAME_MAX個字符,一次最多可打開FOPEN_MAX個文件(在<stdio.h>中定義)。

8.1.2 freopen

FILE *freopen(const char *filename, const char *mode, FILE *stream); 返回:成功爲stream,失敗爲NULL

以mode指定的方式打開文件filename,並使該文件與流stream相關聯。freopen()先嚐試關閉與stream關聯的文件,不管成功與否,都繼續打開新文件。

該函數的主要用途是把系統定義的標準流stdin、stdout、stderr重定向到其他文件。

8.1.3 fflush

int fflush(FILE *stream); 返回:成功爲0,失敗返回EOF

對輸出流(寫打開),fflush()用於將已寫到緩衝區但尚未寫出的全部數據都寫到文件中;對輸入流,其結果未定義。如果寫過程中發生錯誤則返回EOF,正常則返回0。

fflush(NULL)用於刷新所有的輸出流。

程序正常結束或緩衝區滿時,緩衝區自動清倉。

8.1.4 fclose

int flcose(FILE *stream); 返回:成功爲0,失敗返回EOF

刷新stream的全部未寫出數據,丟棄任何未讀的緩衝區內的輸入數據並釋放自動分配的緩衝區,最後關閉流。

8.1.5 remove

int remove(const char *filename); 返回:成功爲0,失敗爲非0值

刪除文件filename。

8.1.6 rename

int rename(const char *oldfname, const char *newfname); 返回:成功爲0,失敗爲非0值

把文件的名字從oldfname改爲newfname。

8.1.7 tmpfile

FILE *tmpfile(void); 返回:成功爲流指針,失敗爲NULL

以方式"wb+"創建一個臨時文件,並返回該流的指針,該文件在被關閉或程序正常結束時被自動刪除。

8.1.8 tmpnam

char *tmpnam(char s[L_tmpnam]); 返回:成功爲非空指針,失敗爲NULL

若參數s爲NULL(即調用tmpnam(NULL)),函數創建一個不同於現存文件名字的字符串,並返回一個指向一內部靜態數組的指針。

若s非空,則函數將所創建的字符串存儲在數組s中,並將它作爲函數值返回。s中至少要有L_tmpnam個字符的空間。

tmpnam函數在每次被調用時均生成不同的名字。在程序的執行過程中,最多隻能確保生成TMP_MAX個不同的名字。注意tmpnam函數只是用於創建一個名字,而不是創建一個文件。

8.1.9 setvbuf

int setvbuf(FILE *stream, char *buf, int mode, size_t size); 返回:成功返回0,失敗返回非0

控制流stream的緩衝區,這要在讀、寫以及其他任何操作之前設置。

如果buf非空,則將buf指向的區域作爲流的緩衝區,如果buf爲NULL,函數將自行分配一個緩衝區。

size決定緩衝區的大小。

mode指定緩衝的處理方式,有如下值:

  • _IOFBF,進行完全緩衝;
  • _IOLBF,對文本文件表示行緩衝;
  • _IOLNF,不設置緩衝。

8.1.10 setbuf

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

如果buf爲NULL,則關閉流stream的的緩衝區;否則setbuf函數等價於:

(void)setvbuf(stream, buf, _IOFBF, BUFSIZ)

注意自定義緩衝區的尺寸必須爲BUFSIZ個字節。

8.2 格式化輸出

8.2.1 fprintf

int fprintf(FILE *stream, const char *format,…); 返回:成功爲實際寫出的字符數,出錯返回負值

按照format說明的格式把變量表中變量內容進行轉換,並寫入stream指向的流。

格式化字符串由兩種類型的對象組成:普通字符(它們被拷貝到輸出流)與轉換規格說明(它們決定變量的轉換和輸出格式)。每個轉換規格說明均以字符%開頭,以轉換字符結束。如果%後面的字符不是轉換字符,那麼該行爲是未定義的。

轉換字符列表如下:

字符 說明
d, i int;有符號十進制表示法
o unsigned int;無符號八進制表示法(無前導0)
x, X unsigned int;無符號十六進制表示法(無前導0X和0x),對0x用abcdef,對0X用ABCDEF
u unsigned int;無符號十進制表示法
c int;單個字符,轉換爲unsigned char類型後輸出
s char *;輸出字符串直到'\0'或者達到精度指定的字符數
f double;形如[-]mmm.ddd的十進制浮點數表示法,d的數目由精度確定。缺省精度爲6位,精度爲0時不輸出小數點
e, E double;形如[-]m.dddddde[+-]xx或者[-]m.ddddddE[+-]xx的十進制浮點數表示法,d的數目由精度確定。缺省精度爲6位,精度爲0時不輸出小數點
g G double;當指數值小於-4或大於等於精度時,採用%e或%E的格式;否則使用%f的格式。尾部的0與小數點不打印
p void *;輸出指針值(具體表示與實現相關)
n int *;到目前爲止以此格式調用函數輸出的字符的數目將被寫入到相應變量中,不進行變量轉換
% 不進行變量轉換,輸出%

在%與轉換字符之間依次可以有下列標記:

標記 說明
- 指定被轉換的變量在其字段內左對齊
+ 指定在輸出的數前面加上正負號
空格 如果第一個字符不是正負號,那麼在其前面附加一個空格
0 對於數值轉換,在輸出長度小於字段寬度時,加前導0
# 指定其他輸出格式,對於o格式,第一個數字必須爲零;對於x/X格式,指定在輸出的非0值前加0x或0X;對於e/E/f/g/G格式,指定輸出總有一個小數點;對於g/GG格式,還指定輸出值後面無意義的0將被保留。
寬度[number] 一個指定最小字段寬的數。轉換後的變量輸出寬度至少要達到這個數值。如果變量的字符數小於此數值,那麼在變量左/右邊添加填充字符。填充字符通常爲空格(設置了0標記則爲0)。
. 點號用於把字段寬和精度分開
精度[number] 對於字符串,說明輸出字符的最大數目;對於e/E/f格式,說明輸出的小數位數;對於g/G格式,說明輸出的有效位數;對於整數,說明輸出的最小位數(必要時可加前導0)
h/l/L 長度修飾符,h表示對應的變量按short或unsigned short類型輸出;l表示對應的變量按long或unsigned long類型輸出;L表示對應的變量按long double類型輸出

在格式串中字段寬度和精度二者都可以用*來指定,此時該值可通過轉換對應的變量來獲得,這些變量必須是int類型。

8.2.2 printf

int printf(const char *format, …);

printf(...)等價於fprintf(stdout, ...)。

8.2.3 sprintf

int sprintf(char *buf, const char *format, …); 返回:實際寫到字符數組的字符數,不包括'\0'

與printf()基本相同,但輸出寫到字符數組buf而不是stdout中,並以'\0'結束。

注意,sprintf()不對buf進行邊界檢查,buf必須足夠大,以便能裝下輸出結果。

8.2.4 snprintf

int snprintf(char *buf, size_t num, const char *format, …);

除了最多爲num-1個字符被存放到buf指向的數組之外,snprintf()和sprintf()完全相同。數組以'\0'結束。

該函數不屬於C89(C99增加的),但應用廣泛,所以將其包括了進來。

8.2.5 vprintf

8.2.6 vfprintf

8.2.7 vsprintf

8.2.8 vsnprintf

int vprintf(char *format, va_list arg); 
int vfprintf(FILE *stream, const char *format, va_list arg); 
int vsprintf(char *buf, const char *format, va_list arg);
 int vsnprintf(char *buf, size_t num, const char *format, va_list arg);

這幾個函數與對應的printf()等價,但變量表由arg代替。參見第7節有關<stdarg.h>頭文件的討論。

vsnprintf是C99增加的。

8.3 格式化輸入

8.3.1 fscanf

int fscanf(FILE *stream, const char *format, …); 返回:成功爲實際被轉換並賦值的輸入項數目, 到達文件尾或變量被轉換前出錯爲EOF

在格式串format的控制下從流stream中讀入字符,把轉換後的值賦給後續各個變量,在此每一個變量都必須是一個指針。當格式串format結束時函數返回。

格式串format通常包含有用於指導輸入轉換的轉換規格說明。格式串中可以包含:

  • 空格或製表符,他們將被忽略;
  • 普通字符(%除外),與輸入流中下一個非空白字符相匹配;
  • 轉換規格說明:由一個%、一個賦值屏蔽字符*(可選)、一個用於指定最大字段寬度的數(可選)、一個用於指定目標字段的字符h/l/L(可選)、一個轉換字符組成。

轉換規格說明決定了輸入字段的轉換方式。通常把結果保存在由對應變量指向的變量中。然而,如果轉換規格說明中包含有賦值屏蔽字符*,例如%*s,那麼就跳過對應的輸入字段,不進行賦值。輸入字段是一個由非空白符組成的字符串,當遇到空白符或到達最大字段寬(如果有的話)時,對輸入字段的讀入結束。這意味着scanf函數可以跨越行的界限來讀入其輸入,因爲換行符也是空白符(空白符包括空格、橫向製表符、縱向製表符、換行符、回車符和換頁符)。

轉換字符列表如下:

字符 輸入數據;變量類型
d 十進制整數;int *
i 整數;int *。該整數可以是以0開頭的八進制數,也可以是以0x/0X開頭的十六進制數
o 八進制數(可以帶或不帶前導0);unsigned int *
u 無符號十進制整數;unsigned int *
x 十六進制整數(可以帶或不帶前導0x/0X);unsigned int *
c 字符;char *。按照字段寬的大小把讀入的字符保存在指定的數組中,不加入字符'\0'。字段寬的缺省值爲1。在這種情況下,不跳過空白符;如果要讀入下一個非空白符,使用%1s(數字1)
s 有非空白符組成的字符串(不包含引號);char *。該變量指針指向一個字符數組,該字符數組有足夠空間來保存該字符串以及在末尾添加的'\0'
e/f/g 浮點數;float *。float浮點數的輸入格式爲:一個任選的正負號,一串可能包含小數點的數字和一個任選的指數字段。指數字段由字母e/E以及後跟的一個可能帶正負號的整數組成
p 用printf("%p")調用輸出的指針值;void *
n 將到目前爲止此調用所讀的字符數寫入變量;int *。不讀入輸入字符。不增加轉換項目計數
[...] 用方括號括起來的字符集中的字符來匹配輸入,以找到最長的非空字符串;char *。在末尾添加'\0'。格式[]...]表示字符集中包含字符]
[^...] 用不在方括號裏的字符集中的字符來匹配輸入,以找到最長的非空字符串;char *。在末尾添加'\0'。格式[]...]表示字符集中包含字符]
% 字面值%,不進行賦值

字段類型字符:

  • 如果變量是指向short類型而不是int類型的指針,那麼在d/i/n/o/u/x這幾個轉換字符前可以加上字符h;
  • 如果變量是指向long類型的指針,那麼在d/i/n/o/u/x這幾個轉換字符前可以加上字符l;
  • 如果變量是指向double類型而不是float類型的指針,那麼在e/f/g這幾個轉換字符前可以加上字符l;
  • 如果變量是指向long double類型的指針,那麼在e/f/g前可以加上字符L。

8.3.2 scanf

#include <stdio.h> int scanf(const char *format, …);

scanf(...)等價於fscanf(stdin, ...)。

8.3.3 sscanf

int sscanf(const char *buf, const char *format, …);

與scanf()基本相同,但sscanf()從buf指向的數組中讀,而不是stdin。

8.4 字符輸入輸出函數

8.4.1 fgetc

int fgetc(FILE *stream);

以unsigned char類型返回輸入流stream中下一個字符(轉換爲int類型)。如果到達文件末尾或發生錯誤,則返回EOF。

8.4.2 fgets

char *fgets(char *str, int num, FILE *stream); 返回:成功返回str,到達文件尾或發生錯誤返回NULL

從流stream中讀入最多num-1個字符到數組str中。當遇到換行符時,把換行符保留在str中,讀入不再進行。數組str以'\0'結尾。

8.4.3 fputc

#include <stdio.h> int fputc(int ch, FILE *stream); 返回:成功爲所寫的字符,出錯爲EOF

把字符ch(轉換爲unsigned char類型)輸出到流stream中。

8.4.4 fputs

int fputs(const char *str, FILE *stream); 返回:成功返回非負值,失敗返回EOF

把字符串str輸出到流stream中,不輸出終止符'\0'。

8.4.5 getc

int getc(FILE *stream);

getc()與fgetc()等價。不同之處爲:當getc函數被定義爲宏時,它可能多次計算stream的值。

8.4.6 getchar

int getchar(void);

等價於getc(stdin)。

8.4.7 gets

char *gets(char *str); 返回:成功爲str,到達文件尾或發生錯誤則爲NULL

從stdin中讀入下一個字符串到數組str中,並把讀入的換行符替換爲字符'\0'。

gets()可讀入無限多字節,所以要保證str有足夠的空間,防止溢出。

8.4.8 putc

int putc(int ch, FILE *stream);

putc()與fputc()等價。不同之處爲:當putc函數被定義爲宏時,它可能多次計算stream的值。

8.4.9 putchar

int putchar(int ch);

等價於putc(ch, stdout)。

8.4.10 puts

int puts(const char *str); 返回:成功返回非負值,出錯返回EOF

把字符串str和一個換行符輸出到stdout。

8.4.11 ungetc

int ungetc(int ch, FILE *stream); 返回:成功時爲ch,出錯爲EOF

把字符ch(轉換爲unsigned char類型)寫回到流stream中,下次對該流進行讀操作時,將返回該字符。對每個流只保證能寫回一個字符(有些實現支持回退多個字符),且此字符不能是EOF。

8.5 直接輸入輸出函數

8.5.1 fread

size_t fread(void *buf, size_t size, size_t count, FILE *stream); 返回:實際讀入的對象數

從流stream中讀入最多count個長度爲size個字節的對象,放到buf指向的數組中。

返回值可能小於指定讀入數,原因可能是出錯,也可能是到達文件尾。實際執行狀態可用feof()或ferror()確定。

8.5.2 fwrite

size_t fwrite(const void *buf, size_t size, size_t count, FILE *stream); 返回:實際輸出的對象數

把buf指向的數組中count個長度爲size的對象輸出到流stream中,並返回被輸出的對象數。如果發生錯誤,則返回一個小於count的值。

8.6 文件定位函數

8.6.1 fseek

int fseek(FILE *stream, long int offset, int origin); 返回:成功爲0,出錯爲非0

對流stream相關的文件定位,隨後的讀寫操作將從新位置開始。

對於二進制文件,此位置被定位在由origin開始的offset個字符處。origin的值可能爲SEEK_SET(文件開始處)、SEEK_CUR(當前位置)或SEEK_END(文件結束處)。

對於文本流,offset心須爲0,或者是由函數ftell()返回的值(此時origin的值必須是SEEK_SET)。

8.6.2 ftell

long int ftell(FILE *stream);

返回與流stream相關的文件的當前位置。出錯時返回-1L。

8.6.3 rewind

void rewind(FILE *stream);

rewind(fp)等價於fssek(fp, 0L, SEEK_SET)與clearerr(fp)這兩個函數順序執行的效果,即把與流stream相關的文件的當前位置移到開始處,同時清除與該流相關的文件尾標誌和錯誤標誌。

8.6.4 fgetpos

int fgetpos(FILE *stream, fpos_t *position); 返回:成功返回0,失敗返回非0

把流stream的當前位置記錄在*position中,供隨後的fsetpos()調用時使用。

8.6.5 fsetpos

int fsetpos(FILE *stream, const fpos_t *position); 返回:成功返回0,失敗返回非0

把流stream的位置定位到*position中記錄的位置。*position的值是之前調用fgetpos()記錄下來的。

8.7 錯誤處理函數

當發生錯誤或到達文件末尾時,標準庫中的許多函數將設置狀態指示符。這些狀態指示符可被顯式地設置和測試。另外,(定義在<errno.h>中的)整數表達式errno可包含一個出錯序號,該數將進一步給出最近一次出錯的信息。

8.7.1 clearerr

void clearerr(FILE *stream);

清除與流stream相關的文件結束指示符和錯誤指示符。

8.7.2 feof

int feof(FILE *stream); 返回:到達文件尾時返回非0值,否則返回0

與流stream相關的文件結束指示符被設置時,函數返回一個非0值。

8.7.3 ferror

int ferror(FILE *stream); 返回:無錯返回0,有錯返回非0

與流stream相關的文件出錯指示符被設置時,函數返回一個非0值。

8.7.4 perror

void perror(const char *str);

perror(s)用於輸出字符串s以及與全局變量errno中的整數值相對應的出錯信息,具體出錯信息的內容依賴於實現。該函數的功能類似於:

fprintf(stderr, "%s: %s\n", s, "出錯信息");

可參見第3節介紹的strerror函數。

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