C语言---14文件操作---01文件内容的顺序读写
文中的源碼都在這里哦!!!
文中的源碼都在這里哦!!!
一、文件的基本概念
-
一個文件通常是磁盤上一段命名的存儲區
-
磁盤文件(通常用的文件):指一組相關數據的有序集合,通常存儲在外部介質(如磁盤)上,使用時才調入內存
-
設備文件(與硬件有關的文件):在操作系統中把每一個與主機相連的輸入、輸出設備看作是一個文件,把它們的輸入、輸出等同于對磁盤文件的讀和寫。例如:鍵盤(標準輸入文件)、屏幕(標準輸出文件)
-
以下說的是磁盤文件
(一)磁盤文件的存取過程
-
磁盤文件,一般保存在硬盤、光盤、U盤等掉電不丟失的磁盤設備中,在需要時調入內存
-
在內存中對文件進行編輯處理后,保存到磁盤中(內存只是文件的處理區,不是存儲區)
-
程序與磁盤之間交互,不是立即完成,系統或程序可根據需要設置緩沖區,以提高存取效率,延長磁盤壽命(在緩沖區進行暫時存儲,直到存儲的數據量達到一定的數量,不然存儲一次打開一次磁盤,會縮短磁盤壽命)
?
(二)文件分類(重要)
1、物理上
-
所有的磁盤文件都是二進制存儲,以字節為單位進行順序存儲(空間是連續的)
2、邏輯上
-
程序文件:有后綴名,主要用于存儲程序代碼
-
數據文件:程序運行時讀寫的數據
-
數據文件可分為ASCII文件(文本文件)和二進制文件——C語言可識別的文件
-
文本文件
-
基于字符編碼,常見編碼有ASCII、UNICODE等,一般可以使用文本編輯器直接打開
-
例如:數5678以ASCII存儲形式為
-
ASCII碼:00110101 00110110 00110111 00111000
-
是每個字符的ASCII碼值
-
效率低,需要查表,但便于查看
-
-
二進制文件
-
基于值編碼,根據應用指定某個值的意思
-
把內存中的數據按其在內存中的存儲形式原樣輸出到磁盤上
-
例如:5678的存儲形式為
-
進制碼:0001 0110 0010 1110
-
讀取效率很高,但是解譯很麻煩,查看麻煩
-
3、兩者的對比
| 編碼基于字符定長,譯碼容易些 | 編碼是變長的,譯碼難一些(不同的二進制文件格式,有不同的譯碼方式) |
| 任何一個符號至少需要一個字節 | 用一個比特來代表一個意思(位操作) |
| 通用的記事本工具就幾乎可以瀏覽所有文本文件 | 需要一個具體的文件解碼器 |
二、文件操作
-
C語言中不能直接操作文件,需要借助庫函數對文件進行操作
-
基本流程
-
在使用文件前要調用打開函數將文件打開,得到文件指針fp
-
然后調用各種有關函數,利用fp對文件進行具體處理(讀或寫)
-
在文件用完時,及時調用關閉函數來關閉文件
-
C語言中所有的文件操作都圍繞文件指針完成(只有通過文件指針,我們才能知道自己操作的是哪個文件),所以操作文件前必須定義一個文件指針指向我們將要操作的文件
(一)文件指針
-
文件指針:指向文件的指針,可以指向文件的內存地址
-
格式:FILE * 指針變量標識符
-
FILE為大寫,需要包含頭文件<stdio.h>
-
FILE是系統使用typedef定義出來的有關文件信息的一種結構體類型,FILE結構體中含有文件名、文件狀態和文件當前位置等信息(不需要關心)
-
c語言中有三個特殊的文件指針無需定義,打開可直接使用(在后續說明中會提到!!!)
-
stdin:標準輸入。默認為當前終端(鍵盤),使用的scanf、getchar函數默認從此終端獲得數據
-
stdout:標準輸出。默認為當前終端(屏幕),使用的printf、puts函數默認輸出信息到此終端
-
stderr:標準出錯。默認為當前終端(屏幕),當我們程序出錯或者使用perror函數時信息打印在此終端
?
(二)打開與關閉文件
-
任何文件使用之前必須打開,使用后必須關閉
1、fopen打開一個文件
-
格式:fp = fopen(文件名,文件打開方式)
-
返回值:返回的是文件的起始地址,執行不成功返回NULL(需要在打開之后判斷是否打開成功)
-
文件名:要操作文件的名字,可包含路徑
-
文件路徑 + 文件名主干 + 文件后綴
-
文件的路徑可以唯一標識文件的位置
-
絕對路徑:從根目錄(盤符)開始的文件路徑 + 文件名 + 文件擴展名(文件類型)
-
相對路徑:相對于當前目錄,從當前目錄開始訪問到某一文件的路徑
-
打開方式:讀、寫、二進制、文本(與文件的存儲方式無關,與操作系統有關)
-
r:以只讀方式打開文件。文件不存在返回NULL;文件存在返回文件指針,進行后續的讀操作
-
w:以只寫方式打開文件。文件不存在以指定文件名創建此文件;文件存在則清空文件內容,進行寫操作;文件打不開,返回NULL
-
a:以追加方式打開文件。文件不存在,以指定文件名創建此文件(同w);若文件存在,從文件的結尾處進行寫操作
-
+:可讀可寫
-
b:以二進制的方式打開文件
-
t:以文本的方式打開文件(省略!!!)
- 不是很重要,了解一下就行?
- 在windows平臺下,當讀取文件的時候,系統會將所有的"\r\n"轉換成"\n";當寫入文件的時候,系統會將"\n"轉換成"\r\n"寫入
- 在Unix/Linux平臺下,“文本”與“二進制”模式沒有區別。\r\n作為兩個字符原樣輸入輸出
-
打開方式的組合形式?
| 模? 式 | 功?? 能 |
| r或rb | 以只讀方式打開一個文本文件(不創建文件) |
| w或wb | 以寫方式打開文件(使文件長度截斷為0字節,創建一個文件) |
| a或ab | 以添加方式打開文件,即在末尾添加內容,當文件不存在時,創建文件用于寫 |
| r+或rb+ | 以可讀、可寫的方式打開文件(不創建新文件) |
| w+或wb+ | 以可讀、可寫的方式打開文件 (使文件長度為0字節,創建一個文件) |
| a+或ab+ | 以添加方式打開文件,打開文件并在末尾更改文件(如果文件不存在,則創建文件) |
-
順序讀寫文件:文件指針會從文件指針當前位置順序讀寫文件,打開文件時,文件指針默認指向文件的開頭?
2、fclose關閉文件
-
格式:fclose(文件指針);
-
正常執行則返回0,不成功則返回-1(EOF)
3、練習
-
以只讀、文本方式打開當前路徑下一個叫test.txt文件
-
以只寫、二進制方式打開同一個文件
-
以追加(a)、文本的方式打開同一個文件
-
同時以讀/寫、二進制方式打開同一個文件,要求若文件不存在,提示出錯
-
同時以讀/些、文本方式打開同一個文件,要求若文件不存在,創建此文件
-
若打開成功則關閉相應的文件
-
對文件操作最常用的是:“讀”和“寫”
-
C語言提供了多種對文件讀寫的函數
-
字節讀寫函數:? fgetc和fputc
-
字符串讀寫函數:fgets和fputs
-
數據塊讀寫函數:fread和fwrite
-
格式化讀寫函數:fscanf和fprintf
-
以上函數可完成對文件內容的順序讀寫
?
(三)文件的字節讀寫(單個字符的輸入輸出)
1、fgetc:字節讀操作
-
格式:ch = fgetc(fp);?
-
說明
-
從指定文件讀取一個字節賦給ch(以“讀”或“讀寫的方式”打開文件)
-
讀取文本文件,讀到文件結尾返回EOF(EOF是在stdio.h文件中定義的符號常量,值為-1)
-
讀二進制文件,讀到文件結尾,使用feof判斷結尾(后面會講)
2、讀操作示例
-
如果本地沒有創建相應的文件,會報錯如下所示
-
事先在本地創建a.txt,文件內容為 hello file
-
文件輸出:buf = hello file
3、fputc:字節的寫操作
-
格式:fputc(ch,fp);
-
說明
-
把一個ch變量中的值(1個字節)寫到指定的文件
-
如果輸出成功,則返回輸出的字節;如果輸出失敗,則返回一個EOF
4、寫操作示例
void test3() {char buf[128] = "";int i = 0;FILE* fp = NULL;fp = fopen("b.txt", "w"); // 沒有就創建if (fp == NULL){perror("fopen");return;}// 使用fputc進行文件的數據寫入printf("請輸入要寫入文件的字符串:");fgets(buf, sizeof(buf), stdin); // 會獲取換行符buf[strlen(buf) - 1] = 0; // 去掉鍵盤輸入的換行符// 將字符串buf中的元素 逐個寫入文件中while (buf[i] != '\0'){fputc(buf[i], fp);i++;}fclose(fp); }5、練習:從a.txt讀取文件內容寫入到b.txt
void test4() {FILE *fp1 =NULL;FILE *fp2 =NULL;// 以只讀的方式打開a.txtfp1 = fopen("a.txt","r");if(fp1 == NULL){perror("fopen");return;}// 以只寫的方式打開b.txtfp2 = fopen("b.txt","w");if(fp2 == NULL){perror("fopen");return;}// 從fp1中每讀取一個字節寫入到fp2中while(1){char ch;// 讀ch = fgetc(fp1);if(ch == EOF) // 已經讀到文件末尾break;// 寫fputc(ch,fp2);}fclose(fp1);fclose(fp2);return; }?
(四)字符串的輸入輸出(文件的字符串讀寫)
1、fputs:往文件中寫入一個字符串
-
格式:fputs("china", fp);
-
說明
-
向指定文件寫入一個字符串
-
第一個參數可以是字符串常量、字符數組、字符指針
-
字符串末尾的'\0'不會寫進文件
2、fgets:從文件中獲取字符串
-
格式:fgets(str, n, fp);
-
說明
-
功能:從fp指向的文件中讀取n-1個字符,在讀取n-1個字符之前遇到換行符或EOF,提前結束讀取并在最后加一個’\0’
-
str:存放數據的首地址
-
返回值:成功讀取則返回讀到字符串的首元素地址,失敗則返回NULL
-
可以讀取換行符
-
用來獲取文件一行的數據
3、綜合示例
void test7() {FILE* fp = NULL;char str[10] = "\0";fp = fopen("test1.txt", "w");fputs("XYZ123*#!", fp); // 將字符串"XYZ123*#!"寫入文件指針fp指向的當前文件位置fclose(fp);fp = fopen("test1.txt", "r+");fgets(str, 8, fp); // 從文件指針fp指向文件的當前位置讀取7個字符存入字符數組str中// 獲取字符的長度會比參數給定的長度小1個,因為需要用于存儲'\0'puts(str);fclose(fp); }4、練習:從一個文件中讀取一個字符串,輸出到另一個文件
void test8() {FILE* fp_r, * fp_w; // 文件讀寫指針char str[100] = "";fp_r = fopen("src.text", "r+");if (fp_r == NULL) // 判斷文件是否正常打開{perror(fopen);return;}fp_w = fopen("dest.text", "w+");if (fp_w == NULL){perror(fopen);return;}// 文本輸入輸出fgets(str, 20, fp_r);puts(str);fputs(str, fp_w);// 鍵盤輸入,屏幕輸出fgets(str, 100, stdin);fputs(str, stdout);fclose(fp_r);fclose(fp_w);return 0; }?
(五) 文件塊的讀寫(以二進制的形式讀寫數據)
1、fwrite:將數據塊寫入到文件中
-
格式:fwrite(buffer,size,count,fp);
-
說明
-
buffer:指向存儲數據空間的首地址的指針
-
size:一次性讀取數據塊大小
-
count:要讀取的數據塊的個數
-
fp:指向要進行寫操作的文件指針
-
返回實際讀寫的數據塊數---count(不是總數據大小哦!!!)
- 查看的時候發現和自己寫入的內容不一樣,這就是文件塊的特點保存的快,但是查看比較麻煩?
2、fread:從文件中讀取數據塊
-
格式:fread(buffer,size,count,fp);
-
參數與fwrite一樣
3、綜合示例
void test11() {FILE* fp = NULL;int arr[6] = { 1, 2, 3, 4, 5, 6 };fp = fopen("test3.txt", "wb"); // 只寫的形式打開二進制文本fwrite(arr, sizeof(int), 6, fp); // 把整型數組arr中6個大小為int類型的數據寫入文件指針fp所指向的文件當前位置fclose(fp);int arr2[6] = { 0 };fp = fopen("test3.txt", "rb");fread(arr2, sizeof(int), 6, fp); // 從文件指針fp所指向文件的當前位置讀取6個整型大小的數據放入數組arr2中for (int i = 0; i < 6; i++)printf("%d\t", arr2[i]);putchar('\n');fclose(fp); }?
4、練習:從鍵盤輸入一個結構體數組數據,輸出到文件,再讀入并顯示
void test12() {struct stu boya[10], boyb[2];FILE* fp = NULL;int i = 0;fp = fopen("test12.txt", "wb+");if (fp == NULL){perror(fopen);return;}printf("請輸入數據:\n");for (; i < 2; i++){scanf("%s %d %d", boya[i].name, &boya[i].num, &boya[i].age);}fwrite(boya, sizeof(boya), 2, fp); // 學生信息寫入文件rewind(fp); // 重新將文件指針指向開頭fread(boyb, sizeof(boyb), 2, fp);for (i = 0; i < 2; i++){printf("%s %d %d", boyb[i].name, boyb[i].num, boyb[i].age);}fclose(fp); }(六)文件的格式化操作(格式化輸入和輸出函數)
-
格式化輸入輸出:以什么格式輸入的就以什么格式輸出
-
針對文件塊查看不便的問題,通過格式化輸入輸出的方法
1、fprintf:格式化寫操作
-
格式:fprintf(文件指針, 格式化字符串, 輸出列表);
?
2、fscanf:格式化讀操作
-
格式:fscanf(文件指針, 格式化字符串, 輸入列表);
?
3、綜合示例
-
優點:對磁盤文件讀寫使用方便,容易理解,直觀的查看
-
缺點:在輸入時將ASCII碼轉換成二進制,在輸出時將二進制轉為字符,花費時間較多
?
?
?(七)格式化輸入輸出與文件塊對比
-
文件拷貝用文件塊read和fwrite函數,速度快,查看不方便
-
文件打印輸出查看用fprintf和fcsanf函數,不在乎時間,需要的是直觀可看
-
在內存與磁盤頻繁交換數據的情況下,最好不用fprintf和fcsanf函數,而使用fread和fwrite函數
總結
以上是生活随笔為你收集整理的C语言---14文件操作---01文件内容的顺序读写的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 宝箱概率问题
- 下一篇: 畅通工程1863(并查集)(WA的思考)