https://mp.weixin.qq.com/s/obcOxx9e6edRHcKYIh4YLQ
[toc]
文件
File (文件)是硬盤磁盤上的被命名的存儲空間。
C 把文件看作是一系列的字節,每個字節都能被單獨讀取。
所有文件的內容都是以二進制存儲的。文本文件以二進制編碼的字符比如ASCLL或Unicode 存儲,二進制文件以機器語言代碼或樹值數據或圖片或音樂編碼存儲。
exit()
函數關閉搜有打開的文件並結束程序,exit(0)
或 exit(EXIT_SUCCESS)
表示成功結束程序, eixt(EXIT_FAILURE)
表示結束程序失敗。
return
會把控制權交給上級函數,直到最初函數。
fopen()
fopen()
函數用於打開文件,第一個參數是地址,第二個參數是打開文件的模式。返回文件指針(指向FILE的指針)。
模式有如下幾個:
模式 | 含義 |
---|---|
"r" | 以只讀模式打開文件 |
"w" | 寫模式,把文件長度截取爲0即文件內容被刪除,文件不存在則創建新的 |
"a" | 寫模式,在文件末尾添加內容,文件不存在則創建新的 |
"r+" | 更新模式,可以讀寫文件 |
"w+" | 更新模式,文件長度截取爲0,文件不存在則創建新的 |
"a+" | 更新模式,只允許在文件末尾添加內容,文件不存在則創建新的,這個模式可以讀取整個文件 |
"rb","wb","ab","rb+","r+b","wb+","w+b","ab+","a+b" | 更新模式,以二進制模式打開文件 |
"wx","wbx","w+x","wb+x,"w+bx" | (C11)類似非x模式,但是如果文件已存在或以獨佔模式打開文件,則打開文件失敗 |
帶x字母的寫模式,即使fopen()操作失敗,原文件的內容也不會被刪除。第二,如果環境允許,x模式的獨佔特性使得其他程序或線程無法訪問正在被打開的文件。
getc()
getc(文件指針)
從文件指針指向的文件獲取一個字符。
putc()
getc(字符,文件指針)
把字符放入文件指針指向的文件中。
fclose()
fclose(文件指針)
關閉文件指針指向的文件,關閉成功返回 0, 否則返回 EOF,必要的時候刷新緩衝區。
示例(1):
// 預編譯器,把stdio.h文件中的所有內容都輸入該行所在的位置, stdio.h 包含了供編譯器使用的輸入輸出函數
#include <stdio.h> // <- C 預處理指令
int main() { // <- 函數體開始
int ch;
FILE * fp = fopen("../test/test.txt", "r");
FILE * fpout = fopen("../test/testout.txt", "w");
ch = getc(fp);
while ((ch = getc(fp)) != EOF) { // 得到一個輸入,判斷是否是文件末尾
putchar(ch);
putc(ch, fpout);
}
if(fclose(fp) != 0){
printf("關閉test文件失敗\n");
}
if(fclose(fpout) != 0){
printf("關閉testout文件失敗\n");
}
return 0; // <- 函數體結束
}
fprintf()
與 printf()
類似,但是又多了一個參數,第一個參數是個文件指針,例如:
fprintf(stderr, "error %s", "error");
fprintf(stdout, "error %s", "error");
stderr
指針用於把錯誤信息發送至標準錯誤。
stdout
指針用於把信息發送至標準輸出。
fprintf(文件指針, "msg %s", "msg");
把信息寫入到 文件指針指向的文件中。
fscanf()
與 scanf()
類似,但是又多了一個參數,第一個參數是個文件指針,例如:
char words[41];
fscanf(stdin, "%40s", words);
從標準輸入讀取信息到 words 中。
fscanf(文件指針, "%s", words);
讀取文件指針指向的文件中的單詞到 words 中。
rewind()
rewind(文件指針)
使程序返回到文件開始處。
fgets()
fgets(字符指針, 字符串大小, 文件指針)
會讀取到第一個換行符,或者文件末尾,或者指定字符串大小個字符。
fgets()
會在字符串末尾加上一個空字符。
fputs()
fputs(字符串地址, 文件指針)
把字符串寫入到指定文件中。
fseek() 和 ftell()
fseek(文件指針, 偏移量, SEEK_SET|SEEK_CUR|SEEK_END)
可以在打開的文件中移動到任意字節處。
ftell()
返回 long 類型值表示文件的當前位置。
-
SEEK_SET
文件開始處; -
SEEK_CUR
當前位置; -
SEEK_END
文件末尾;
long last;
FILE * fp = fopen("../test/test.txt", "rb");
// 定位到文件末尾
fseek(fp, 0, SEEK_END);
int ch;
last = ftell(fp);
for (long i = 1; i <= last; ++i) {
// 定位到文件末尾的前 i 位
fseek(fp, -i, SEEK_END);
ch = getc(fp);
putchar(ch);
}
fclose(fp);
fgetpos() 和 fsetpos()
突破 fseek() 和 ftell() 的 long 限制。
fpos_t
: 文件定位類型, 它的對象或變量可以指定文件中的一個位置。
int fgetpos(FILE * __restrict, fpos_t * restrict pos);
成功返回0,否則非0,獲取當前位置並存入pos
, pos
指向的是 fpos_t
類型值,描述文件當前位置到文件開頭的字節數字。
int fsetpos(FILE *, const fpos_t * restrict pos);
成功返回0,失敗返回非0,設置文件指針指向的位置。
ungetc()
int ungetc(int c, FILE *fp);
函數把c指定的字符放回輸入流中。如果把一個字符放回輸入流,下次調用標準輸入函數時將讀取該字符。
fflush()
int fflush(FILE *fp);
刷新緩衝區,調用fflush()函數引起輸出緩衝區中所有的未寫入數據被髮送到fp指定的輸出文件。
setvbuf()
在打開文件後且未對流進行其他操作之前,調用它創建緩衝區。
int setvbuf(FILE * __restrict fp, char * __restrict buf, int mode, size_t size);
創建了一個供標準I/O函數替換使用的緩衝區, 成功返回0,否則非0.
fp
: 待處理的流;
buf
: 待使用的存儲區, 如果是 NULL 會自動創建;
mode
: _IOFBF
完全緩衝區即緩衝區慢點時候刷新,_IONBF
無緩衝 ;
size
: size_t 派生整數類型,數組的大小;
fwrite()
函數用於二進制形式的數據寫入處理。
size_t fwrite(const void * __restrict __ptr, size_t __size, size_t __nitems, FILE * __restrict __stream);
把二進制數據寫入文件, 返回成功寫入項目的數量;
size_t
是 unsigned int
, 是 sizeof
運算符返回的類型;size表示待寫入數據塊的大小(以字節爲單位);nmemb表示待寫入數據塊的數量;
例如: 保存 含有10個 double類型值的數組
double a[10];
fwrite(a, sizeof(double), 10, fp);
fread()
函數用於二進制形式的數據寫入處理。
size_t fread(void * __restrict __ptr, size_t __size, size_t __nitems, FILE * __restrict __stream);
讀取被 fwrite() 寫入文件的數據, 返回成功讀取項的數量;
例如: 讀取含有 10 個 double 類型值的數組,並拷貝到 oa 中,
double oa[10];
fread(oa, sizeof(double), 10, fp);
feof() ferror()
int feof(FILE *);
int ferror(FILE *);
文件末尾時,函數返回 EOF,但是文件出錯也返回 EOF,這兩個函數就是來判斷這兩個情景的。
當上一次輸入調用檢測到文件結尾時,feof()函數返回一個非零值,否則返回0。當讀或寫出現錯誤,ferror()函數返回一個非零值,否則返回0。
示例
獲取文件名
char * s_gets(char * st, int n{
char * ret_val;
char * find;
ret_val = fgets(st, n, stdin);
if(ret_val){
find = strchr(st, '\n');//查找換行符
if(find) //如果地址不是NULL,
*find='\0'; //在此處放置一個空字符
else
while(getchar() != '\n')
continue;
}
return ret_val;
}
拷貝
記得要給文件創建緩衝區
if(setvbuf( fa, NULL, _IOFBF, BUFSIZE) != 0){
fputs("無法創建緩衝區\n", stderr);
exit(EXIT_FAILURE);
}
void append(FILE * source, FILE * dest){
size_t bytes;
static char temp[BUFSIZE];//只分配一次
while((bytes = fread(temp, sizeof(char), BUFSIZE, source)) > 0)
fwrite(temp, sizeof(char), bytes, dest);
}
總結
當輸入函數發現已讀完緩衝區中的所有字符時,會請求把下一個緩衝大小的數據塊從文件拷貝到該緩衝區中。以這種方式,輸入函數可以讀取文件中的所有內容,直到文件結尾。函數在讀取緩衝區中的最後一個字符後,把結尾指示器設置爲真。於是,下一次被調用的輸入函數將返回EOF。輸出函數以類似的方式把數據寫入緩衝區。當緩衝區被填滿時,數據將被拷貝至文件中。
fopen()函數爲標準I/O打開一個文件,並創建一個用於存儲文件和緩衝區信息的結構。
feof()和ferror()函數報告I/O操作失敗的原因。