Linux 標準I/O庫

標準I/O庫處理不少細節,如緩衝區分配、以優化的塊長度執行I/O等。這些處理使用戶沒必要擔憂如何選擇正確的塊長度。數組

緩衝

標準I/O庫提供緩衝的目的是儘量減小使用read和write的調用次數。標準I/O提供了3種類型的緩衝。安全

  1. 全緩衝。在這種狀況下,在填滿標準I/O緩衝區後才進行實際的I/O操做。對於駐留在磁盤上的文件一般是由標準I/O庫實施全緩衝的。flush說明標準I/O緩衝區的寫操做。緩衝區可由標準I/O例程自動flush,或者能夠調用函數fflush沖洗一個流。
  2. 行緩衝。在這種狀況下,當輸入和輸出中遇到換行符時,標準I/O庫執行I/O操做。當流涉及一個終端時,一般使用行緩衝。
  3. 不帶緩衝。標準I/O庫不對字符進行緩衝存儲。標準錯誤流stderr一般是不帶緩衝的,這就使得出錯信息能夠儘快顯示出來。

對於任何一個給定的流,若是咱們不喜歡這些系統默認,則可調用下列兩個函數中的一個更改緩衝類型。網絡

#include <stdio.h>

void setbuf(FILE *fp, char *buf);
int setvbuf(FILE *fp, char *buf, int mode, size_t size);

返回值:若成功,返回0;若出錯,返回非0

可使用setbuf函數打開或關閉緩衝機制。爲了帶緩衝I/O,參數buf必須指向一個長度爲BUFSIZ的緩衝區(該常量定義在<stdio.h>中)。一般在此以後該流就是全緩衝的。爲了關閉緩衝,將buf設置爲NULL。函數

使用setvbuf函數,能夠精確的說明所需的緩衝類型。這是用mode參數實現的:優化

  • _IOFBF 全緩衝
  • _IOLBF 行緩衝
  • _IONBF 不帶緩衝

若是指定一個不帶緩衝的流,則忽略buf和size參數。若是指定全緩衝或行緩衝,則buf和size可選擇地指定一個緩衝區及其長度。若是該流是帶緩衝的,而buf是NULL,則標準I/O庫將自動地爲該流分配適當長度的緩衝區。適當長度指的是由常量BUFSIZ所指定的值。spa

通常而言,應由系統選擇緩衝區的長度,並自動分配緩衝區。指針

任什麼時候候,咱們均可以用fflush函數沖洗一個流。code

#include <stdio.h>

int fflush(FILE *fp);

返回值:若成功,返回0;若出錯,返回EOF

打開流

#include <stdio.h>

FILE *fopen(const char *pathname, const char *type);
FILE *freopen(const char *pathname, const char *type, FILE *fp);
FILE *fdopen(int fd, const char *type);

3個函數返回值:若成功,返回文件指針;若出錯,返回NULL

這三個函數的區別以下。orm

  1. fopen函數打開路徑名爲pathname的一個指定的文件。
  2. freopen函數再一個指定的流上打開一個指定的文件,如該流已經打開,則先關閉該流。如該流已經定向,則使用freopen清除該定向。此函數通常用於將一個指定的文件打開爲一個預約義的流:標準輸入、標準輸出或標準錯誤。
  3. fdopen函數取一個已有的文件描述符,並使一個標準的I/O流與該描述符相結合。此函數經常使用於由建立管道和網絡通訊通道函數返回的描述符。由於這些特殊類型文件不能用標準I/O函數fopen

參數type指定對該I/O流的讀寫方式。對象

type 說明 open(2)標誌
r或rb 爲讀而打開 O_RDONLY
w或wb 把文件截斷至0,或爲寫而建立 O_WRONLY | O_CREAT | O_TRUNC
a或ab 追加;爲在文件尾寫而打開,或爲寫而建立 O_WRONLY | O_CREAT | O_APPEND
r+或r+b或rb+ 爲讀和寫而打開 O_RDWR
w+或w+b或wb+ 把文件截斷至0長,或爲讀和寫而打開 O_RDWR | O_CREAT | O_TRUNC
a+或a+b或ab+ 爲在文件尾讀和寫而打開或建立 O_RDWR | O_CREAT | O_APPEND

除非流引用了終端設備,不然按系統默認,流被打開時是全緩衝的。若流引用終端設備,則該流是行緩衝的。

調用fclose關閉一個打開的流。

#include <stdio.h>

int fclose(FILE *fp);

返回值:若成功,返回0;若出錯,返回EOF

在該文件被關閉以前,沖洗緩衝中的輸出數據。當一個進程正常終止時,則全部帶未寫緩衝數據的標準I/O流都被沖洗,全部打開的標準I/O流都被關閉。

讀寫流

一旦打開了流,則可在三種不一樣類型的非格式化I/O中進行選擇,對其進行讀寫操做。

  1. 每次一個字符的I/O。
  2. 每次一行的I/O。若是想要每次讀或寫一行,則使用fgets或fputs。每次都以換行符終止。當調用fgets時,應說明能處理的最大行長度。
  3. 直接I/O。fread和fwrite函數支持這種類型的I/O。這兩個函數經常使用於從二進制文件中每次讀或寫一個結構。

每次一個字符I/O

#include <stdio.h>

int getc(FILE *fp);
int fgetc(FILE *fp);
int getchar(void);

三個函數的返回值:若成功,返回下一個字符;若已到達文件尾或出錯,返回EOF

前兩個函數的區別是,getc可被實現爲宏,而fgetc不能實現爲宏。這意味着如下幾點。

  1. getc的參數不能是具備反作用的表達式。
  2. 由於fgetc必定是一個函數,因此能夠獲得其地址。這就容許將fgetc的地址做爲一個參數傳送給另外一個函數。
  3. 調用fgetc所需的時間極可能比調用getc要長,由於調用函數的時間一般長於調用宏。

注意,不論是到達文件尾仍是出錯,這三個函數都返回相同的值。爲了區分不一樣的狀況,必須調用ferror或feof。

#include <stdio.h>

int ferror(FILE *fp);
int feof(FILE *fp);
兩個函數返回值:若條件爲真,返回非0;不然,返回0

void clearerr(FILE *fp);

大多數實現中,爲每一個流在FILE對象中維護了兩個標誌:出錯標誌;文件結束標誌。調用clearerr能夠清除這兩個標誌。

對應於getc,fgetc和getchar三個輸入函數,輸出函數以下。

#include <stdio.h>

int putc(int c, FILE *fp);
int fputc(int c, FILE *fp);
int putchar(int c);

三個函數返回值:若成功,返回c;若出錯,返回EOF

每次一行I/O

如下兩個函數提供每次輸入一行的功能。

#include <stdio.h>

char *fgets(char *buf, int n, FILE *fp);
char *gets(char *buf);

兩個函數返回值:若成功,返回buf;若已到達文件尾或出錯,返回NULL

gets從標準輸入讀,而fgets從指定的流讀。對於fgets,必須指定緩衝的長度n,此函數一直讀到寫一個換行符爲止,可是不超過n-1個字符,讀入的字符被送入緩衝區。該緩衝區以null字符結尾。若是改行包括最後一個換行符的字符數超過n-1,則fgets只返回一個不完整的行,可是,緩衝區老是以null字符結尾。對fgets的下一次調用會繼續讀該行。gets是一個不推薦使用的函數。其問題是調用者在使用gets時不能指定緩衝區的長度。這有可能致使內存溢出,產生不可預料的結果。

fputs和puts提供每次輸出一行的功能。

#include <stdio.h>

int fputs(const char *str, FILE *fp);
int puts(const char *str);

兩個函數返回值:若成功,返回非負值;若出錯,返回EOF

函數fputs將一個以null字符終止的字符串寫到指定的流,尾端的null字符不寫出。puts將一個以null字符終止的字符串寫到標準輸出,null字符不寫出。可是,puts隨後又將一個換行符寫到標準輸出。

二進制I/O

#include <stdio.h>

size_t fread(void *ptr, size_t size, size_t nobj, FILE *fp);
size_t fwrite(const void *ptr, size_t size, size_t nobj, FILE *fp);

兩個函數返回值:讀或寫的對象數

fread和fwrite返回讀或寫的對象數。對於讀,若是出錯或到達文件尾端,則此數字能夠少於nobj。在這種狀況應該用ferror或feof以判斷到底是哪種狀況。對於寫,若是返回值少於nobj,則出錯。

定位流

有三種方式能夠定位標準I/O流。

  1. ftell和fseek函數。它們都假定文件的位置能夠存放在一個長整形中。
  2. ftello和fseeko函數。它們用off_t代替了long。
  3. fgetpos和fsetpos函數。它們使用一個抽象數據類型fpos_t記錄文件位置。這種數據類型能夠根據須要定義爲一個足夠大的數,用以記錄文件位置。
#include <stdio.h>

long ftell(FILE *fp);
返回值:若成功,返回當前文件位置指示;若出錯,返回-1L

int fseek(FILE *fp, long offset, int whence);
返回值:若成功,返回0;若出錯,返回-1

void rewind(FILE *fp);

使用rewind函數也能夠將一個流設置到文件的起始位置。

除了偏移量的類型是off_t之外,ftello函數與ftell相同,fseeko與fseek相同。

#include <stdio.h>

off_t ftello(FILE *fp);
返回值:若成功,返回當前文件位置;若出錯,返回(off_t)-1

int fseeko(FILE *fp, off_t offset, int whence);
返回值:若成功,返回0;若出錯,返回-1
#include <stdio.h>

int fgetpos(FILE *fp, fpos_t *pos);
int fsetpos(FILE *fp, const fpos_t *pos);

兩個函數返回值:若成功,返回0;若出錯,返回-1

fgetpos將文件位置指示器的當前值存入pos指向的對象中。在之後調用fsetpos時,可使用此值將流從新定位至該位置。

格式化I/O

5個格式化輸出函數。

#include <stdio.h>

int printf(const char *format, ...);
int fprintf(FILE *fp, const char *format, ...);
int dprintf(int fd, const char *format, ...);
三個函數返回值:若成功,返回輸出字符數;若輸出錯誤,返回負值

int sprintf(char *buf, const char *format, ...);
返回值:若成功,返回存入數組的字符數;若出錯,返回負值

int snprintf(char *buf, size_t n, const char *format, ...);
返回值:若緩衝區足夠大,返回將要存入數組的字符數;若出錯,返回負值

printf將格式化數據寫到標準輸出,fprintf寫到指定的流,dprintf寫到指定的文件描述符,sprintf將格式化數據寫入buf中,sprintf自動在buf尾端添加null字符,但null字符不包含在返回值中。snprintf指定了緩衝區的長度,若是輸入的字符數超過緩衝區長度,則將被丟棄。使用snprintf更加安全。

5個格式化輸出函數的變體,將可變參數換成了arg。

#include <stdarg.h>
#include <stdio.h>

int vprintf(const char *format, va_list arg);
int vfprintf(FILE *fp, const char *format, va_list arg);
int vdprintf(int fd, const char *format, va_list arg);
3個函數的返回值:若成功,返回輸出的字符數;若出錯,返回負值

int vsprintf(char *buf, const char *format, va_list arg);
返回值:若成功,返回存入數組的字符數;若出錯,返回負值

int vsnprintf(char *buf, size_t n, const char *format, va_list arg);
返回值:若緩衝區足夠大,返回存入數組的字符數;若出錯,返回負值

格式化輸出轉換說明

一個轉換說明有4個可選的部分。

%[flags][fieldwidth][precision][lenmodifier]convtype
  1. flags
    標誌 說明
    ' 將整數按千位分組字符
    - 在字段內左對齊輸出
    + 老是顯示帶符號轉換的正負號
    space 若是第一個字符不是正負號,則在其前面加上空格
    # 指定另外一種轉換形式(例如,對於十六進制格式,加0x前綴)
    0 添加前導0(而非空格)進行填充
  2. fieldwidth。說明最小字段寬度。轉換後字符數若小於寬度,則多餘字符位置用空格填充。字符寬度是一個非負十進制整數,或者是一個星號(*)。
  3. precision。
  4. lenmodifier。
  5. convtype。

對於轉換說明請參考APUE的第128頁到129頁的詳細說明。

格式化輸入函數

#include <stdio.h>

int scanf(const char *format, ...);
int fscanf(FILE *fp, const char *format, ...);
int sscanf(const char *buf, const char *format, ...);

三個函數的返回值:賦值的輸入項數;若輸入出錯或在任一轉換前已經到達文件尾端,返回EOF
#include <stdarg.h>
#include <stdio.h>

int vscanf(const char *format, va_list arg);
int vfscanf(FILE *fp, const char *format, va_list arg);
int vsscanf(const char *buf, const char *format, va_list arg);

三個函數返回值:指定的輸入項目數;若出錯或在任一轉換前文件結束,返回EOF

可使用fileno函數獲取流的文件描述符。

#include <stdio.h>

int fileno(FILE *fp);

返回值:與該流相關的文件描述符

臨時文件

ISO C標準庫提供了兩個函數以幫助建立臨時文件。

#include <stdio.h>

char *tmpnam(char *ptr);
返回值:指向惟一路徑名的指針

FILE *tmpfile(void);
返回值:若成功,返回文件指針;若出錯,返回NULL

tmpnam產生一個與現有文件名不一樣的有效路徑名字符串。tmpfile建立一個臨時二進制文件(wb+),在關閉該文件或程序結束時將自動刪除該文件。

Single UNIX Specification爲處理臨時文件定義了另外兩個函數。

#include <stdlib.h>

char *mkdtemp(char *template);
返回值:若成功,返回指向目錄名的指針;若出錯,返回NULL

int mkstemp(char *template);
返回值:若成功,返回文件描述符;若出錯,返回-1

內存流

有3個函數能夠用於內存流的建立。

#include <stdio.h>

FILE *fmemopen(void *buf, size_t size, const char *type);
返回值:若成功,返回流指針;若錯誤,返回NULL
相關文章
相關標籤/搜索