是很多人學(xué)C語(yǔ)言接觸的第一個(gè)頭文件,顧名思義,stdio就是"標(biāo)準(zhǔn)輸入輸出",其中聲明了一組關(guān)于輸入輸出的類(lèi)型,宏和函數(shù),其中就包括了打印著名的"hello,world!"的printf(),但是,這并不意味著這個(gè)頭文件就很簡(jiǎn)單,相反,這個(gè)頭文件是C標(biāo)準(zhǔn)庫(kù)里唯二包羅萬(wàn)象的一個(gè)庫(kù)(另一個(gè)是)。好,讓我們從頭審視一下這個(gè)頭文件
概念
文件描述符file descriptor
似于Windows系統(tǒng)的文件句柄,Unix/Linux系統(tǒng)用來(lái)描述文件的一個(gè)正整數(shù),OS負(fù)責(zé)分發(fā)文件描述符給程序員,并把關(guān)于這個(gè)文件細(xì)節(jié)的控制信息存儲(chǔ)在自己的專(zhuān)用內(nèi)存中,這些信息由OS維護(hù),不需要程序員費(fèi)心思。
文本VS二進(jìn)制
在ANSI C編程可以指定文件的打開(kāi)方式是按照"二進(jìn)制"還是"文本"方式,如果在Unix系統(tǒng)這種不區(qū)分"文本"和"二進(jìn)制"的系統(tǒng)中,可以省略這種指定,但是畢竟很多OS還是對(duì)這兩種文件類(lèi)型加以區(qū)分的,所以最好還是進(jìn)行明確的指定以便實(shí)現(xiàn)可移植性。
流stream
ANSI C將對(duì)文件讀寫(xiě)看作是數(shù)據(jù)的流出和流入,而隱藏了文件物理存儲(chǔ)介質(zhì)的不同,即不論這個(gè)文件是存儲(chǔ)的磁盤(pán),內(nèi)存,F(xiàn)LASH還是其他地方,在程序員看來(lái)都只是一個(gè)文件,而對(duì)一個(gè)文件的處理都是數(shù)據(jù)的流入和流出。打開(kāi)一個(gè)文件會(huì)把一個(gè)物理介質(zhì)上的文件連接到流的一端。通過(guò)流來(lái)對(duì)實(shí)際的文件進(jìn)行讀寫(xiě),關(guān)閉一個(gè)文件會(huì)把一個(gè)物理介質(zhì)上的文件和流斷開(kāi)。
ANSI C規(guī)定了兩種流——文本流和二進(jìn)制流,前者將數(shù)據(jù)看作字符,即201609是6個(gè)字符'2','0','1','6','0','9',占6byte,而在二進(jìn)制流中,這就是int,占4byte。此外,文本流也會(huì)將'\n'轉(zhuǎn)換成'回車(chē)CR'和'換行LR'兩個(gè)字符,而二進(jìn)制流不會(huì)。從這兩個(gè)角度看,二進(jìn)制流的流動(dòng)速度比文本流更快,也更省存儲(chǔ)空間
數(shù)據(jù)類(lèi)型
size_t
FILE
FILE是ANSIC中用來(lái)保存文件信息的一個(gè)結(jié)構(gòu)體,使用ANSI C編程時(shí)打開(kāi)一個(gè)文件就是得到的就是一個(gè)FILE*(文件指針),如果是使用UNix/Linux系統(tǒng)下的編譯器,那么任何通過(guò)對(duì)FILE*對(duì)文件的操作底層都是使用文件描述符來(lái)實(shí)現(xiàn)的,當(dāng)然其他平臺(tái)的具體實(shí)現(xiàn)還可能不一樣
//gcc 4.9.2中對(duì)FILE類(lèi)型的聲明typedef struct _IO_FILE FILE;struct _IO_FILE { int _flags; char* _IO_read_ptr; char* _IO_read_end; char* _IO_read_base; char* _IO_write_base; char* _IO_write_ptr; char* _IO_write_end; char* _IO_buf_base; char* _IO_buf_end; char *_IO_save_base; char *_IO_backup_base; char *_IO_save_end; struct _IO_marker *_markers; struct _IO_FILE *_chain; int _fileno; int _flags2; __off_t _old_offset; unsigned short _cur_column; signed char _vtable_offset; char _shortbuf[1]; _IO_lock_t *_lock;# 293 "/usr/include/libio.h" 3 4 __off64_t _offset;# 302 "/usr/include/libio.h" 3 4 void *__pad1; void *__pad2; void *__pad3; void *__pad4; size_t __pad5; int _mode; char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];};typedef struct _IO_FILE _IO_FILE;
fpos_t
fpos_t可以唯一指定文件中的每個(gè)位置所需的所有信息,實(shí)際上是一個(gè)整型變量,用來(lái)記錄當(dāng)前讀寫(xiě)位置距離文件開(kāi)頭的byte數(shù),很多文件讀寫(xiě)函數(shù)在讀寫(xiě)一次后都會(huì)改寫(xiě)這個(gè)變量的值
宏
NULL
_IOFBF, _IOLBF, _IONBF
這三個(gè)宏展開(kāi)為具有不同值的常量表達(dá)式,是個(gè)作為函數(shù)setvbuf的第三個(gè)arg
BUFSIZ
展開(kāi)為一個(gè)整型常量表達(dá)式,只setbuf()緩沖池的大小
EOF
End of File,展開(kāi)為一個(gè)負(fù)的整型常量表達(dá)式,表示一個(gè)流結(jié)束了
FOPEN_MAX
展開(kāi)為一個(gè)整型常量表達(dá)式,表示當(dāng)前環(huán)境下可以同時(shí)打開(kāi)文件數(shù)目的最大數(shù)目
FILENAME_MAX
展開(kāi)為一個(gè)整型常量表達(dá)式,表示用來(lái)保存文件名的char數(shù)組的大小,即文件名的最大長(zhǎng)度
L_tmpnam
展開(kāi)為一個(gè)整型常量表達(dá)式,表示用來(lái)保存tmpnam()生成的臨時(shí)文件名串的char數(shù)組的大小
SEEK_CUR, SEEK_END, SEEK_SET
展開(kāi)為不同值的整型常量表達(dá)式,用作fseek()函數(shù)的arg
TMP_MAX
展開(kāi)為一個(gè)整型常量表達(dá)式,表示tmpnam()可以聲場(chǎng)的單獨(dú)文件名的最小數(shù)目
stderr, stdin, stdout
展開(kāi)為一個(gè)"FILE*"類(lèi)型的表達(dá)式,分別指向標(biāo)準(zhǔn)錯(cuò)誤流,標(biāo)準(zhǔn)輸入流,標(biāo)準(zhǔn)輸出流,Unix/Linux系統(tǒng)中這三個(gè)流默認(rèn)分別是顯示器,鍵盤(pán),顯示器
函數(shù)
文件訪問(wèn)
remove()
/*功能:導(dǎo)致一個(gè)文件再也不能通過(guò)它的文件名filename訪問(wèn),除非重新創(chuàng)建該文件返回值:成功返回0,否則返回非0*/int remove(const char* filename);
rename()
/*功能:把名字為oldname的文件改名為newname返回值:*/int rename(const char* oldname,const char* newname);
tmpfile()
/*功能:創(chuàng)建一個(gè)臨時(shí)二進(jìn)制文件,文件被關(guān)閉就會(huì)被移除返回值:成功返回FILE*,否則返回void\*FILE* tmpfile(void);
tmpnam()
//生成一個(gè)有效的文件名char* tmpnam(char* s);
fclose()
/*功能:將stream指向的流被清空,并且和流相關(guān)聯(lián)的文件被關(guān)閉,流中任何未寫(xiě)出的緩沖數(shù)據(jù)都傳遞到環(huán)境并寫(xiě)入文件,任何未讀的都被丟棄。返回值:成功返回0,否則返回EOF*/int fclose(FILE* stream);
fflush()
/*功能:清空stream指向的流,未寫(xiě)入文件的會(huì)被寫(xiě)入,未讀的丟棄參數(shù):流stream返回值:*/int fflush(FILE* stream);
fopen()
/*功能:打開(kāi)以串filename為名的文件,并把這個(gè)文件和一個(gè)流相連參數(shù):文件名字符串filename,打開(kāi)方式mode如下:r 只讀w 清空寫(xiě)a 追加寫(xiě)b 放在rwa之后,表示"以二進(jìn)制方式"+ 放在rwa之后,表示"文件不存在就創(chuàng)建"返回值:成功返回FILE*,失敗返回void**/FILE* fopen(const char* filename,const char* mode);
freopen()
/*功能:打開(kāi)路徑為filename指向的串文件,并把這個(gè)文件和流stream相連返回值:成功返回stream的值,否則返回void**/FILE* freopen(const char* filename, const char* mode,FILE* stream);
setvbuf()
/*功能:指定流stream緩沖的方式,只能在流和一個(gè)文件關(guān)聯(lián)后,但還沒(méi)有對(duì)流進(jìn)行其他操作之前使用參數(shù):mode指定流緩沖的方式,_IOFBF表示完全緩沖,即緩沖區(qū)滿才對(duì)文件操作,_IOLBF表示輸入/輸出行緩沖,即緩沖區(qū)中遇到換行就對(duì)文件進(jìn)行操作,_IONBF表示輸入/輸出不換沖,如果buf不是void*,則可以用它指向的數(shù)組來(lái)代替setvbuf()自動(dòng)分配的緩沖區(qū),size指定了數(shù)組的大小。返回值:成功返回0,否則返回非0; */int setvbuf(FILE* stream, char* buf, int mode, size_t size);
setbuf()
/* 功能:如果buf不是void*,相當(dāng)于mode為_(kāi)IOFBF,size為BUFSIZd調(diào)用setvbuf(),如果哦buf是void*,相當(dāng)于mode為_(kāi)IONBF調(diào)用setvbuf()返回值:無(wú)*/void setbuf(FILE* stream, char* buf);
格式化輸出輸出
fprintf()
/*功能:按照f(shuō)ormat指向的格式控制串把輸出寫(xiě)入stream指向的流參數(shù):返回值:成功返回輸出項(xiàng)的數(shù)目,失敗返回EOF*/int fprintf(FILE* stream, const char* format,...);
fscanf()
/*功能:按照f(shuō)ormat指向的格式控制串,把后面的參數(shù)作為指向接收轉(zhuǎn)換后的輸入的對(duì)象的指針參數(shù):返回值:成功返回輸入項(xiàng)的數(shù)目,失敗返回EOF*/int fscanf(FILE* stream, const char* format, ...);
printf()
/*功能:相當(dāng)于fprintf(),只是把stdout作為stream參數(shù):返回值:成功返回輸出項(xiàng)的數(shù)目,否則返回負(fù)值*/int printf(const char* format, ...);
scanf()
/*功能:相當(dāng)于fsanf(),只是把stdin作為stream參數(shù):返回值:成功返回輸入項(xiàng)的數(shù)目,失敗返回EOF*/int scanf(const char* formant, ...);
sprintf()
/*功能:相當(dāng)于fprintf(),只是把本來(lái)寫(xiě)入流stream的內(nèi)容改為寫(xiě)入到數(shù)組s中參數(shù):返回值:成功寫(xiě)入數(shù)組中字符的數(shù)目,不包括NUL*/int sprintf(char *s, const char* format, ...);
ssanf()
/*功能:相當(dāng)于fscanf(),只是把本來(lái)從流stream獲取的內(nèi)容改為從數(shù)組s獲取參數(shù):返回值:成功輸入項(xiàng)的數(shù)目,否則返回EOF*/int sscanf(const char* s, const char* format, ...);
vfprintf()
/*功能:相當(dāng)于fprintf(),只是把可變參數(shù)表用arg代替參數(shù):返回值:成功返回輸出項(xiàng)的數(shù)目,否則返回一個(gè)負(fù)數(shù)*/int vfprintf(FILE* stream, const char* format, va_list arg);
vprintf()
/*功能:相當(dāng)于printf(),只是把可變參數(shù)表用arg代替參數(shù):返回值:成功返回輸出項(xiàng)的數(shù)目,否則返回一個(gè)負(fù)數(shù)*/int vprintf(const char* format, va_list arg);
vsprintf()
/*功能:相當(dāng)于sprintf(),只是把可變參數(shù)用arg代替參數(shù):返回值:成功返回輸出項(xiàng)的數(shù)目,否則返回一個(gè)負(fù)數(shù)*/int vsprintf(char* s, const char* format, va_list arg);
字符輸出輸出
fgetc()
/*功能:從stream指向的輸入流中讀取下一個(gè)字符,并把它由unsigned char轉(zhuǎn)換為int參數(shù):返回值:成功返回讀取到的字符,否則返回EOF*/int fgetc(FILE* stream);
fgets()
/*功能:從stream指向的流中讀取字符,讀取字符的數(shù)目最多為n-1,因?yàn)橹辽龠€要給NUL留位置,然后將字符寫(xiě)入到數(shù)組s中,如果敲入"123回車(chē)"存儲(chǔ)的是"123\0",這個(gè)函數(shù)會(huì)自動(dòng)把輸入的'\n'變成'\0',這點(diǎn)和scanf()不同參數(shù):返回值:*/char* fgets(char* s, int n, FILE* stream);
fputc()
/*功能:把c字符寫(xiě)入到stream指向的輸出流中的文件定位符指定的位置,并將位置指針移動(dòng)一個(gè)參數(shù):返回值:*/int fputc(int c, FILE* stream);
fputs()
/*功能:把s串的有效字符寫(xiě)入stream參數(shù):返回值:成功返回一個(gè)非負(fù)值,否則返回EOF*/int fputs(const char* s, FILE* stream);
getc()
/*功能:相當(dāng)于fgetc(),只是如果getc()作為一個(gè)宏實(shí)現(xiàn)時(shí),可能會(huì)對(duì)stream進(jìn)行多次進(jìn)算,所以它的參數(shù)不能是有副作用的表達(dá)式參數(shù):返回值:*/int getc(FILE* stream);
getchar()
/*功能:相當(dāng)于fgetc(),只是從stream獲取改為從stdin獲取參數(shù):返回值:*/int getchar(void);
gets()
/*功能:有的資料說(shuō)相當(dāng)于fgets(),只是從stream獲取改為從stdin獲取,直到遇到一個(gè)換行符,其實(shí)gets和fgets最大的區(qū)別就是不回進(jìn)行輸入字符數(shù)目的限制,一旦用戶輸入的字符個(gè)數(shù)超過(guò)了接收buf的大小,就可能引發(fā)錯(cuò)誤,所以不建議使用這個(gè)函數(shù)參數(shù):返回值:*/char* gets(char* s);
putc()
/*功能:相當(dāng)于fputc(),只是如果putc()作為一個(gè)宏實(shí)現(xiàn)時(shí),可能會(huì)對(duì)stream進(jìn)行多次暈眩,所以它的參數(shù)不能是有副作用的表達(dá)式參數(shù):返回值:*/int putc(int c, FILE* stream);
putchar()
/*功能:相當(dāng)于fputc(),只是輸出到stream改為輸出到stdout參數(shù):返回值:*/int putchar(int c);
puts()
/*功能:相當(dāng)于fputs(),只是輸出到stream改為輸出到stdout參數(shù):返回值:*/int puts(const char* s);
ungetc()
/*功能:把c字符退回到stream參數(shù):返回值:*/int ungetc(int c, FILE* stream);
直接輸入輸出
fread()
/*功能:從stream中讀取最多nmemb個(gè)元素到ptr指向的數(shù)組中參數(shù):返回值:成功返回讀取的元素的個(gè)數(shù)*/size_t fread(void *ptr, size_t size, size_t nmemb, FILE* stream);
fwrite()
/*功能:從ptr指向的數(shù)組中讀取最多nmemb個(gè)元素并將其寫(xiě)到stream中參數(shù):返回值:*/size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream);
文件定位函數(shù)
fgetpos()
/*功能:把stream中的定位符的當(dāng)前值存儲(chǔ)到pos指向的對(duì)象中參數(shù):返回值:*/int fgetpos(FILE* stream, fpos_t* pos);
fseek()
/*功能:為stream設(shè)置文件定位符參數(shù):offset表示以whence為基準(zhǔn)的偏移量,whence有三種值:SEEK_SET表示以文件開(kāi)頭為基準(zhǔn),SEEK_CUR表示以當(dāng)前文件定位符位置為基準(zhǔn),SEEK_END表示以文件結(jié)尾為基準(zhǔn)返回值:成功返回0,否則返回非0*/int fseek(FILE* stream, long int offset, int whence);
fsetpos()
/*功能:根據(jù)pos指向的對(duì)象的值來(lái)設(shè)置stream中定位符的位置參數(shù):返回值:成功返回0,否則返回非0,并設(shè)置errno*/int fsetpos(FILE* stream, const fpos_t* pos);
ftell()
/*功能:獲得stream定位符的當(dāng)前值參數(shù):返回值:返回文件定位符當(dāng)前值,否則返回-1L,并設(shè)置errno*/long int ftell(FILE* stream);
rewind()
/*功能:把stream的文件定位符設(shè)置在文件的開(kāi)始位置,等價(jià)于(void) fseek(stram, 0L,SEEK_SET)參數(shù):返回值:*/void rewind(FILE* stream);
錯(cuò)誤處理
clearerr()
/*功能:清空stream指向的流文件結(jié)束符和錯(cuò)誤指示符參數(shù):返回值:*/void clearerr(FILE* stream);
feof()
/*功能:測(cè)試stream的文件結(jié)束符參數(shù):返回值:如果stream設(shè)置了文件結(jié)束符返回一個(gè)非0*/int feof(FILE* stream);
ferror()
/*功能:測(cè)試stream指向的流的錯(cuò)誤提示符參數(shù):返回值:如果stream設(shè)置了錯(cuò)誤提示符返回非0*/int ferror(FILE* stream);
perror()
/*功能:把errno轉(zhuǎn)換成一個(gè)human-readable的信息參數(shù):返回值:*/void perror(const char* s);
?
評(píng)論