第五章 標準I/O庫
1、流和FILE對象
對於標準I/O庫,它們的操作是圍繞流進行的。流的定向決定了所讀、寫的字符是單字節還是多字節的。
#include <stdio.h>
#include <wchar.h>
int fwide(FILE *fp,int mode);
//返回值:若流是寬定向的,返回正值;若流是字節定向的,返回負值;若流是未定向的,返回0.
fwide函數可用於流的定向。根據mode參數的不同值,fwide函數執行不同的工作。
若mode參數值爲負,fwide將試圖使指定的流是字節定向的
若mode參數值爲正,fwide將試圖使指定的流是寬定向的
若mode參數值是0,fwide將不試圖設置流的定向,但返回標誌該流定向的值
當一個流最初被創建時,它並沒有定向。若在未定向的流上使用一個多字節(單字節)I/O函數,則將該流設置爲寬(字節)定向。fwide並不改變已定向流的定向。
2、標準輸入、標準輸出和標準錯誤
對一個進程預定義了3個流:stdin、stdout、stderr。這些流引用的文件與文件描述符STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO所引用的相同。
3、緩衝
標準I/O庫提供緩衝的目的是儘可能減少使用read和write調用的次數,標準I/O提供了以下3種類型的緩衝:
a、全緩衝,在這種情況下,在填滿標準I/O緩衝區後才進行實際I/O操作。如磁盤上的文件通常實施全緩衝。
b、行緩衝,在這種情況下,當在輸入和輸出中遇到換行符,標準I/O執行I/O操作。如標準輸入輸出。
c、不帶緩衝,標準I/O庫不對字符進行緩衝存儲。標準錯誤流stderr通常是不帶緩衝的。
我們可以調用下面兩個函數更改緩衝類型
#include <stdio.h>
void setbuf(FILE *restrict fp,char *restrict buf);
int setvbuf(FILE *restrict fp,char *buf,int mode,size_t size);
//返回值:若成功,返回0;若出錯,返回非0.
可以使用setbuf打開或關閉緩衝機制,參數buf指定一個長度爲BUFSIZ的緩衝區。將buf設置爲NULL可以關閉緩衝。
使用setvbuf,我們可以精確地說明所需的緩衝類型。這是用mode參數實現的:
_IOFBF 全緩衝
_IOLBF 行緩衝
_IONBF 不帶緩衝
我們可以通過fflush函數沖洗一個流,此函數使該流所有未寫的數據都被傳送至內核。
#include <stdio.h>
int fflush(FILE *fp);
//返回值:若成功,返回0;若出錯,返回EOF。
4、打開流
下面3個函數打開一個標準I/O流
#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。
這三個函數的區別如下:
(1)、fopen函數打開路徑名爲pathname的一個指定的文件;
(2)、freopen函數在一個指定的流上打開一個指定的文件,如若該流已經打開,則先關閉該流。若該流已經定向,則使用freopen清除該定向。此函數一般用於將一個指定的文件打開爲一個預定義的流:標準輸入、標準輸出或標準錯誤。
(3)、fdopen函數取一個已有的文件描述符,並使一個標準的I/O流與該描述符相結合。此函數常用於由創建管道和網絡通信通道函數返回的描述符,因爲這些特殊類型的文件不能用標準I/O函數fopen打開。
type參數指定對該I/O流的讀、寫方式,ISO C規定type參數可以有如下15種不同的值:
其中b作爲type的一部分,這使得標準I/O系統可以區分文本文件和二進制文件。
調用fclose關閉一個打開的流
#include <stdio.h>
int fclose(FILE *fp);
//返回值:若成功,返回0;若出錯,返回EOF。
在該文件被關閉之前,沖洗緩衝中的輸出數據。緩衝區中的任何輸入數據被丟棄。如果標準I/O庫已經爲該流自動分配了一個緩衝區,則釋放該緩衝區。當一個進程正常終止時,則所有帶未寫緩衝數據的標準I/O流都被沖洗,所有打開的標準I/O流都被關閉。
5、讀寫流
以下3個函數可用於一次讀一個字符
#include <stdio.h>
int getc(FILE *fp);
int fgetc(FILE *fp);
int getchar(void); //等同於getc(stdin)
//返回值:若成功,返回下一個字符;若已到達文件尾端或出錯,返回EOF。
對應上面所述的每個輸入函數都有一個輸出函數
#include <stdio.h>
int putc(int c,FILE *fp);
int fputc(int c,FILE *fp);
int putchar(int c);
//返回值:若成功,返回c;若出錯,返回EOF。
不管是出錯還是到達文件尾端,三個輸入函數都返回同樣的值,可以用下面的函數區分:
#include<stdio.h>
Int ferror(FILE *fp);
Int feof(FILE *fp);
兩個函數返回值:若條件爲真,返回非0,否則,返回0.
void clearerr(FILE *fp);
在大多數實現中,爲每個流在FILE對象中維護兩個標誌:出錯標誌和文件結束標誌調用clearerr可以清除這兩個標誌。
從流中讀取數據後,可以調用ungetc將字符再壓送回流中。
#include<stdio.h>
Int ungetc(int c,FILE *fp);
返回值:若成功,返回c;若出錯,返回EOF。
6、每次一行I/O
下面兩個函數提供每次輸入一行的功能
#include <stdio.h>
char *fgets(char *restrict buf,int n,FILE *restrict fp); //buf爲緩衝區地址,讀入的行將送入其中,參數n指定緩衝的長度
char *gets(char *buf); //從標準輸入讀,不推薦使用
//返回值:若成功,返回buf;若已到達文件尾端或出錯,返回NULL。
fputs和puts提供每次輸出一行的功能
#include <stdio.h>
int fputs(const char *restrict str,FILE *restrict fp);
int puts(const char *str);
//返回值:若成功,返回非負值;若出錯,返回EOF。
函數fputs將一個以null字節終止的字符串寫到指定的流,而puts寫到標準輸出。
7、二進制I/O
下列兩個函數執行二進制I/O操作
#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);
參數size爲欲寫結構的長度,nobj爲欲寫的元素個數,函數返回的是讀或寫的對象數。這些函數有以下兩種常見的用法
//(1)、讀或寫一個二進制數組:
float data[10];
if(fwrite(&data[2],sizeof(float),4,fp)!=4)
err_sys("fwrite error");
//(2)、讀寫一個結構
struct{
short count;
long total;
char name[NAMESIZE];
}item;
if(fwrite(&item,sizeof(item),1,fp)!=1)
err_sys("fwrite error");
8、定位流
有3種方法定位標準I/O流
#include <stdio.h>
long ftell(FILE *fp);
返回值:若成功,則返回當前文件位置指示,出錯則返回-lL
int fseek(FILE *fp,long offset,int whence);
返回值:若成功,返回0;若出錯,返回-1;
void rewind(FILE *fp);
除了偏移量的類型是off_t而非long以外,ftello函數與ftell相同,fseeko函數與fseek相同
#include <stdio.h>
off_t ftello(FILE *fp);
int fseeko(FILE *fp,off_t offset,int whence);
下面函數是ISO C標準引入的
#include <stdio.h>
int fgetpos(FILE *restrict fp,fpos_t *restrict pos);
int fsetpos(FILE *fp,const fpos_t *pos);
返回值:若成功,返回0;若出錯,返回非0.
fgetpos將文件位置指示器的當前值存入由pos指向的對象中,在以後調用fsetpos時,可以使用此值將流重新定位至該位置。
9、格式化I/O
格式化輸出是由printf函數處理的
#include <stdio.h>
int printf(const char *restrict format,...);
int fprintf(FILE *restrict fp,const char *restrict format,...);
int dprintf(int fd,const char *restrict format,...);
//三個函數返回值:若成功,返回輸出字節數;若出錯,返回負值
int sprintf(char *restrict buf,const char *restrict format,...);
//返回值:若成功,返回存入數組的字符數;若出錯,返回負值。
int snprintf(char *restrict buf,size_t n,const char *restrict format,...); //參數n指定緩衝區長度
//返回值:若緩衝區足夠大,返回將要存入數組的字符數;若出錯,返回負值。
執行格式化輸入處理的是3個scanf函數
#include <stdio.h>
int scanf(const char *restrict format,...);
int fscanf(FILE *restrict fp,const char *restrict format,...);
int sscanf(const char *restrict buf,const char *restrict format,...);
//三個函數返回值:賦值的輸入項數;若輸入出錯或在任一轉換前已到達文件文件尾端,返回EOF。
10、臨時文件
ISO C標準I/O庫提供了兩個函數以幫助創建臨時文件
#include <stdio.h>
char *tmpnam(char *ptr);
//返回值:指向唯一路徑名的指針。
FILE *tmpfile(void);
//返回值:若成功,返回文件指針;若出錯,返回NULL。
tmpnam函數產生一個與現有文件名不同的一個有效路徑名字符串,tmpfile創建一個臨時二進制文件(類型wb+),在關閉該文件或程序結束時將自動刪除。
參考:http://www.cnblogs.com/runnyu/p/4635382.html