目錄
- 1 文件的概念
- 2 程序文件和數據文件
- 3 二進制文件和文本文件
- 4 流
- 4.1 流的概念
- 4.2 標準流
- 5 文件信息區和文件指針
- 6 處理文件的庫函數
- 6.1 fopen
- 6.2 fclose
- 6.3 fgetc
- 6.4 fputc
- 6.5 fgets
- 6.6 fputs
- 6.7 fscanf
- 6.8 fprintf
- 6.9 fread
- 6.10 fwrite
- 6.11 fseek
- 6.12 ftell
- 6.13 rewind
- 6.14 feof 和 ferror
- 7 文件緩沖區
1 文件的概念
在磁盤中,用于保存數據的工具就是文件
比如,下圖的 test.txt 就是一個文件,保存了 1 2 3 4 5 6 7 8 9 10 這樣的數據
2 程序文件和數據文件
從程序設計的角度上來說,文件主要分為程序文件和數據文件
程序文件:用于保存程序代碼的文件,比如.c后綴的源文件,.h后綴的頭文件
數據文件:用于保存其它數據的文件,比如上文提到的 test.txt 文件
3 二進制文件和文本文件
在C語言編程中,對文件進行操作時,主要有二進制文件和文本文件兩個對象,它們都屬于數據文件
文本文件:數據在保存到文件時,會先將該數據按字節為單位轉換為字符,再以ASCII碼的形式保存
二進制文件:數據在保存到文件時,會直接以二進制序列的形式保存
舉例:1000在文本文件和二進制文件中的不同保存形式
4 流
4.1 流的概念
由于計算機在運行時,會與各種各樣的外部設備交流,所以這會使得程序員需要掌握這些設備的輸入輸出方式,對程序員的要求大大提高,為避免這種現象的發生,提出了流的概念,流向程序員提供了一種便捷的輸入輸出方式,程序員只需要通過流,就可以直接與外部設備進行交互,不需要關心具體輸入輸出的細節
4.2 標準流
標準流主要有3個,分別是 stdin,stdout,stderr
stdin:標準輸入流,用來從鍵盤上讀取數據,scanf 所使用的流就是它
stdout:標準輸出流,用來向屏幕輸出數據,printf 所使用的流就是它
stderr:標準錯誤流,用來在屏幕上顯示錯誤信息
C語言的程序啟動時,默認就開啟了這三個流
5 文件信息區和文件指針
打開文件時,會在內存中生成一個文件信息區,文件信息區本質是一個結構體(名為FILE),保存了文件的各種信息
用戶可以通過指向文件信息區的文件指針來訪問對應的文件,文件指針的類型為FILE*
6 處理文件的庫函數
6.1 fopen
fopen 的函數聲明如下:
FILE* fopen (const char* filename, const char* mode);
功能
打開一個文件
參數
filename 指要打開的文件的名稱
mode 指文件的打開方式
返回值
若文件打開成功,則會返回指向該文件文件信息區的文件指針
若文件打開失敗,則會返回空指針
文件的打開方式
值 | 功能 | 文件不存在時 |
---|---|---|
“r” | 指定本次打開要進行 讀文件 操作,對象為文本文件 | 出錯 |
“w” | 指定本次打開要進行 寫文件 操作并清空文件數據,對象為文本文件 | 創建新文件 |
“a” | 在文件末尾添加新內容,對象為文本文件 | 創建新文件 |
“rb” | 指定本次打開要進行 讀文件 操作,對象為二進制文件 | 出錯 |
“wb” | 指定本次打開要進行 讀文件 操作,對象為二進制文件 | 創建新文件 |
“ab” | 在文件末尾添加新內容,對象為二進制文件 | 創建新文件 |
“r+” | 指定本次打開要進行 讀文件和寫文件 操作,對象為文本文件 | 出錯 |
“w+” | 指定本次打開要進行 讀文件和寫文件 操作,對象為文本文件 | 創建新文件 |
“a+” | 在文件末尾添加新內容,對象為文本文件 | 創建新文件 |
“rb+” | 指定本次打開要進行 讀文件和寫文件 操作,對象為二進制文件 | 出錯 |
“wb+” | 指定本次打開要進行 讀文件和寫文件 操作,對象為二進制文件 | 創建新文件 |
“ab+” | 在文件末尾添加新內容,對象為二進制文件 | 創建新文件 |
舉例:以讀的形式,打開一個名為 “test.txt” 的文本文件
#include <stdio.h>
int main()
{FILE* pf = fopen("test.txt", "r"); //以讀的方式打開文件if (pf == NULL) //防止使用空指針assert(pf);fclose(pf); //關閉文件pf = NULL;return 0;
}
6.2 fclose
int fclose ( FILE * stream );
功能
用于關閉打開的文件
參數
stream 為指向要關閉文件的文件指針
6.3 fgetc
int fgetc ( FILE * stream );
功能
用來從文件中獲取一個字符
參數
stream 為指向要讀取文件的文件指針
返回值
若讀取成功,返回讀取到的字符
若讀取失敗或者遇到文件末尾,返回EOF
舉例:從文件中讀取一個字符并輸出
#include <stdio.h>
#include <assert.h>
int main()
{FILE* pf = fopen("test.txt", "r");if (pf == NULL)assert(pf);printf("%c", (char)fgetc(pf));fclose(pf);pf = NULL;return 0;
}
6.4 fputc
int fputc ( int character, FILE * stream );
功能
用來向文件中寫入字符
參數
character 為要寫入的字符
stream 為指向要操作的文件的文件指針
返回值
若操作成功,則返回寫入的字符
若操作失敗,則返回EOF
舉例:寫一個字符到文件內
#include <stdio.h>
#include <assert.h>
int main()
{FILE* pf = fopen("test.txt", "w");if (pf == NULL)assert(pf);fputc('a', pf);fclose(pf);pf = NULL;return 0;
}
6.5 fgets
char * fgets ( char * str, int num, FILE * stream );
功能
用來從文件中讀出 num-1 個字符,放入 str 指向的字符串內,最后自動補 ‘\0’
參數
str 為指向存放字符的字符串的指針
num 為要讀的字符數量,實際讀取數量為 num-1
stream 為指向要讀的文件的文件指針
返回值
若操作成功,則返回存放讀取字符的字符串首地址
若操作失敗,則返回空指針
舉例:讀取文件中的 4 個字符到字符串內
#include <stdio.h>
#include <assert.h>
int main()
{FILE* pf = fopen("test.txt", "r");if (pf == NULL)assert(pf);char str[5] = " ";fgets(str, 5, pf);fclose(pf);pf = NULL;return 0;
}
6.6 fputs
int fputs ( const char * str, FILE * stream );
功能
將字符串的內容寫到文件中
參數
str 為指向字符串的指針
stream 為指向要寫的文件的指針
返回值
操作成功時,返回非負值
操作失敗時,返回EOF
舉例:讀取一個字符串到文件內
#include <stdio.h>
#include <assert.h>
int main()
{FILE* pf = fopen("test.txt", "w");if (pf == NULL)assert(pf);char str[20] = "hello world";fputs(str, pf);fclose(pf);pf = NULL;return 0;
}
6.7 fscanf
int fscanf ( FILE * stream, const char * format, parameterList );
功能
根據給出的格式,從文件中讀取內容到后方的變量中
參數
stream 為指向要讀的文件的文件指針
format 為需要用戶指定的格式,比如%d,%s等
paramterList 為要存放數據的變量,可以有1個或多個
返回值
返回成功讀取的數據的量
如果在讀取的中途出錯或遇到文件尾,會設置 ferror 或 feof 指示器
如果一個數據都沒有讀取成功,返回EOF
舉例:讀取文件中的數據到變量中
#include <stdio.h>
#include <assert.h>
int main()
{FILE* pf = fopen("test.txt", "w");if (pf == NULL)assert(pf);char str[20] = " ";fscanf(pf, "%s", str);fclose(pf);pf = NULL;return 0;
}
6.8 fprintf
int fprintf ( FILE * stream, const char * format, parameterList);
功能
根據給出的格式,將對應變量中的值寫入文件中
參數
stream 為指向要寫的文件的指針
format 為需要用戶指定的格式,比如%d,%s等
paramterList 為要讀取的變量,可以有1個或多個
返回值
操作成功,則返回成功寫入的字符的數量
操作失敗,返回負數
舉例:寫入數據到文件中
#include <stdio.h>
#include <assert.h>
int main()
{FILE* pf = fopen("test.txt", "w");if (pf == NULL)assert(pf);char str[20] = "hello world";printf("%d", fprintf(pf, "%s", str));fclose(pf);pf = NULL;return 0;
}
6.9 fread
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
功能
從文件中讀取 count 個 size 大小的數據到 ptr 指向的空間內,但是是以二進制的形式進行讀取
參數
ptr 為指向最終存放數據的空間的指針
size 是讀取的每個元素的大小,單位為字節
count 是讀取的元素個數
stream 是指向要讀取的文件的文件指針
返回值
返回成功讀取的元素的個數
舉例:從文件中讀取5個4字節的數據至數組中
#include <stdio.h>
#include <assert.h>
int main()
{FILE* pf = fopen("test.txt", "rb");if (pf == NULL)assert(pf);int arr[5] = { 0 };fread(arr, sizeof(int), 5, pf);fclose(pf);pf = NULL;return 0;
}
6.10 fwrite
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
功能
從 ptr 指向的空間內讀取 count 個 size 大小的數據并以二進制的形式寫到文件內,
參數
ptr 為指向要讀取的空間的指針
size 每個元素的大小
count 為元素的個數
stream 為指向要寫入數據的文件的指針
返回值
返回成功寫入的元素的個數
舉例:向文件中寫入5個4字節的數據
#include <stdio.h>
#include <assert.h>
int main()
{FILE* pf = fopen("test.txt", "wb");if (pf == NULL)assert(pf);int arr[5] = { 1,2,3,4,5 };fwrite(arr, sizeof(int), 5, pf);fclose(pf);pf = NULL;return 0;
}
6.11 fseek
int fseek ( FILE * stream, long int offset, int origin );
功能
通過文件指針的位置,偏移量來移動文件指針
參數
stream 是指向文件的文件指針
offset 是偏移量,用來計算新的文件指針位置
origin 是文件指針的位置,有以下三個取值
取值 | 含義 |
---|---|
SEEK_SET | 文件的起始位置 |
SEEK_CUR | 當前文件指針的位置 |
SEEK_END | 文件的末尾 |
返回值
操作成功,返回0
操作失敗,返回非0
舉例:讀取下面這個文件的d字符
#include <stdio.h>
#include <assert.h>
int main()
{FILE* pf = fopen("test.txt", "r");if (pf == NULL)assert(pf);fseek(pf, 3, SEEK_CUR);printf("%c", fgetc(pf));fclose(pf);pf = NULL;return 0;
}
圖解:
注意事項
若 origin 取值為 SEEK_END ,則偏移量需要給入負數,才能讀取前面的值
6.12 ftell
long int ftell ( FILE * stream );
功能
返回當前文件指針相對于起始位置的偏移量
參數
stream 為指向文件的文件指針
返回值
成功返回當前文件指針的位置
錯誤返回 -1L
舉例:計算下面文件的文件尾相對于起始位置的偏移量
#include <stdio.h>
#include <assert.h>
int main()
{FILE* pf = fopen("test.txt", "r");if (pf == NULL)assert(pf);while (fgetc(pf) != EOF); //使文件指針遍歷到結尾printf("%d", ftell(pf));fclose(pf);pf = NULL;return 0;
}
圖解:
6.13 rewind
void rewind ( FILE * stream );
功能
將文件指針重置到文件的開始位置
參數
stream 為指向文件的文件指針
返回值
無
舉例:輸出兩次下列文件的內容
#include <stdio.h>
#include <assert.h>
int main()
{FILE* pf = fopen("test.txt", "r");if (pf == NULL)assert(pf);char ch = 0;while ((ch = fgetc(pf)) != EOF){printf("%c ", ch);}printf("\n", ch);rewind(pf); //重置文件指針的位置while ((ch = fgetc(pf)) != EOF){printf("%c ", ch);}fclose(pf);pf = NULL;return 0;
}
6.14 feof 和 ferror
int feof ( FILE * stream );
功能
判斷文件的讀取是否因為遇到了文件尾而結束
參數
stream 為指向文件的文件指針
返回值
是遇到了文件尾而結束,則返回非0
不是則返回0
int ferror ( FILE * stream );
功能
判斷文件的讀取是否因為遇到了錯誤而結束
參數
stream 為指向文件的文件指針
返回值
是遇到了錯誤而結束則返回非0
不是則返回0
我們可以通過使用 feof 和 ferror 來讓文件的讀取更加安全
#include <stdio.h>
#include <assert.h>
int main()
{FILE* pf = fopen("test.txt", "r");if (pf == NULL)assert(pf);char ch = 0;while ((ch = fgetc(pf)) != EOF){printf("%c ", ch);}if (feof(pf)){printf("遇到文件尾結束");}else if (ferror(pf)){perror("fault");}fclose(pf);pf = NULL;return 0;
}
7 文件緩沖區
計算機在從文件內讀取數據或向文件內寫入數據時,會先將數據存入輸入/輸出緩沖區,待輸入/輸出緩沖區被填滿時,才會將數據讀入計算機或輸入到文件內,如果沒有緩沖區的話,那么就會出現輸入/輸出一次數據,操作系統就要介入進行處理的情況,操作系統不斷被打斷,無法服務于其它的進程,會使得操作系統的效率降低