3.標準文件IO

標準IO庫

標準IO庫處理有很多細節,例如緩沖區分配、以優化的塊長度執行IO等。

1.流和FILE對象

對于標準IO庫,所有操作都是圍繞進行的,當用標準IO庫打開或創建一個文件時,就使一個流與一個文件相關聯。

流的定向決定讀寫字符是單字節還是多字節字符集(多字節對應寬定向,單字節對應字節定向)。fwide用于設置流的定向:

#include <stdio.h>
#include <wchar.h>
int fwide(FILE *fp, int mode);
/* 返回值:寬定向為正值;字節定向為負值;流是未定向,返回0 */

由于fwide無出錯返回,因此在調用fwide前先清除errno,從fwrite返回時,檢查errno的值。

2.緩沖

為了不頻繁使用writeread,標準IO庫提供了緩沖:

  • 全緩沖,填滿標準IO緩沖區后進行實際IO操作
  • 行緩沖,遇到換行符或者填滿行緩沖區后進行操作
  • 不緩沖,不緩沖,直接輸出

通過下列兩個函數可以對緩沖類型進行修改:

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

/* 返回值:成功返回0,失敗返回非0 */

使用mode參數說明所需的緩沖類型:

mode參數 類型
_IOFBF 全緩沖
_IOLBF 行緩沖
_IONBF 不緩沖

若不使用緩沖,則忽略bufsize參數。

3.打開流

下列3個函數用于打開流:

#include <stdio.h>
FILE *fopen(const char *restrict pathname, const char *restrict type);
FILE *freopen(const char *restrict pathname, const char *restrict type, FILE *restrict fp);
FILE *fdopen(int fd, const char *type);
/* 返回值:成功返回文件指針,失敗返回NULL */

三者區別在于:

  • fopen 打開路徑名為pathname的一個指定文件
  • freopen 在一個指定的流上打開一個指定的文件,若該流已經打開,則先關閉該流。若該流已經定向,則使用freopen清除該定向。此函數一般用于將指定文件打開為一個預定義的流:標準輸入,輸出和錯誤
  • fdopen取一個已有的文件描述符(可能從open,dup,pipe,socket得到此描述符),并使一個標準IO流與該描述符向結合。此函數常用于創建管道和網絡通信管道函數返回的描述符。

使用fclose可以關閉一個打開的流,在文件被關閉前,沖洗緩沖中的輸出數據,并丟棄緩沖區中任何輸入數據,并且釋放此緩沖區。

一個進程正常終止時,則所有帶未寫緩沖數據的標志IO都會被沖洗,所有打開的標準IO流都被關閉。

4.讀和寫流

打開流之后,可以對其進行讀寫操作。

輸入函數

以下3個函數用于一次讀一個字符:

#include <stdio.h> 
int getc(FILE *fp); 
int fgetc(FILE *fp); 
int getchar(void);
/* 返回值:成功返回下一個字符;若到達尾端或者出錯返回EOF */

getchar等同于getc(stdin)。前兩個函數區別在于,getc可被實現為宏,而fgetc不能,這就意味著:

  • getc的參數不應當具有副作用的表達式
  • fgetc一定是個函數,可以通過函數指針傳遞給另一個函數
  • 調用fgetc所需時間可能比getc更長

輸出函數

對應輸入函數都有一個輸出函數:

#include <stdio.h>
int putc(int c, FILE *fp); 
int fputc(int c, FILE *fp); 
int putchar(int c);
/* 返回值:成功返回c,出錯返回EOF*/

與輸入函數一樣,putchar(c)等同于putc(c,stdout)putc可以被實現為宏。

5.每次一行IO

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

#include <stdio.h>
char *fgets(char *restrict buf, int n, FILE *restrict fp); 
char *gets(char *buf);
/* 返回值:成返回buf;若到達尾端或者出錯返回NULL*/

盡量使用fgets防止緩沖區溢出。

對應輸出一行的功能:

#include <stdio.h>
int fputs(const char *restrict str, FILE *restrict fp); 
int puts(const char *str);
/* 返回值:成功返回非負值,出錯返回EOF*/

fputs將一個null字節終止的字符串寫到指定的流,puts除了null,隨后添加了一個換行符到標準輸出。

如果總是使用fgetsfputs,那么久會熟知在每行終止處我們必須字節處理換行符。

6.二進制IO

前面的輸入函數只能一次性讀取一個字節或者一行數據,為了獲得整個結構,提供了下列兩個函數用以執行二進制IO操作:

#include <stdio.h>
size_t fread(void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp);
size_t fwrite(const void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp);

讀寫一個結構體,可以如下:

struct {
    short  count;
    long   total;
    char   name[NAMESIZE];
} item;
if (fwrite(&item, sizeof(item), 1, fp) != 1)
    err_sys("fwrite error");
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • tags:io categories:總結 date: 2017-03-28 22:49:50 不僅僅在JAVA領...
    行徑行閱讀 2,210評論 0 3
  • C/C++輸入輸出流總結 前兩天寫C++實習作業,突然發現I/O是那么的陌生,打了好長時間的文件都沒有打開,今天終...
    LuckTime閱讀 1,752評論 0 6
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,287評論 25 708
  • 最近幾天忙著招待婆家的姐姐們。累!剛從河北回來,跑來跑去,腳,不再是我的了。夜晚沒睡好,眼睛生痛。大家庭的熱鬧實在...
    老美子閱讀 155評論 0 0