c語言--文件操作

思維導圖:

?1. 為什么使用文件?

如果沒有件,我們寫的程序的數據是存儲在電腦的內存中,如果程序退出,內存回收,數據就丟失了,等再次運?程序,是看不到上次程序的數據的,如果要將數據進?持久化的保存,我們可以使?件。

2. 什么是文件?

磁盤(硬盤)上的?件是件。
但是在程序設計中,我們?般談的件有兩種:程序件、數據件(從?件功能的?度來分類
的)。

2.1 程序文件

程序?件包括源程序?件(后綴為.c),?標件(windows環境后綴為.obj),可執?程序(windows環境后綴為.exe)。

2.2 數據文件

?件的內容不?定是程序,?是程序運?時讀寫的數據,?如程序運?需要從中讀取數據的?件,或者輸出內容的?件。
本章討論的是數據?件。
在以前各章所處理數據的輸?輸出都是以終端為對象的,即從終端的鍵盤輸?數據,運?結果顯?到顯?器上。
其實有時候我們會把信息輸出到磁盤上,當需要的時候再從磁盤上把數據讀取到內存中使?,這?處理的就是磁盤上?件。

2.3 文件名

?個?件要有?個唯?的?件標識,以便??識別和引?。
?件名包含3部分:?件路徑+?件名主?+?件后綴
例如: c:\code\test.txt
為了?便起?,?件標識常被稱為?件名。

2.4 常見文件后綴

計算機中的文件后綴非常多,不同后綴對應不同的文件類型和用途。

一、程序文件(可執行或包含代碼)

?? ???? ?.exe:Windows系統的可執行程序(如軟件、游戲啟動文件)。

?? ???? ?.msi:Windows的安裝包程序(用于安裝軟件)。

?? ???? ?.bat / .cmd:Windows的批處理腳本(可自動執行一系列命令)。

?? ???? ?.sh:Linux/macOS的腳本文件(類似批處理,可執行命令)。

?? ???? ?.c / .cpp / .java / .py / .js:各種編程語言的源文件(包含代碼,需編譯/解釋后執行)。

?? ???? ?.class:Java編譯后的字節碼文件(可被Java虛擬機執行)。

?? ???? ?.app:macOS的應用程序(本質是包含可執行文件的文件夾)。

?? ???? ?.apk:安卓系統的安裝包(包含手機應用的可執行代碼)。

二、數據文件(存儲內容,需對應程序打開)

1. 文檔類

?? ???? ?.txt:純文本文件(記事本可打開)。

?? ???? ?.docx / .doc:Word文檔(文字、格式)。

?? ???? ?.xlsx / .xls:Excel表格(數據、公式)。

?? ???? ?.pptx / .ppt:PowerPoint演示文稿(幻燈片)。

?? ???? ?.pdf:便攜文檔格式(跨平臺的只讀文檔)。

2. 媒體類

?? ???? ?.jpg / .jpeg / .png / .gif:圖片文件(分別對應不同壓縮格式)。

?? ???? ?.mp3 / .wav / .flac:音頻文件(音樂、聲音)。

?? ???? ?.mp4 / .avi / .mov / .mkv:視頻文件(電影、視頻片段)。

3. 壓縮/備份類

?? ???? ?.zip / .rar / .7z:壓縮包(用于打包多個文件,節省空間)。

?? ???? ?.iso:光盤鏡像文件(可模擬光盤內容,用于安裝系統、游戲)。

4. 其他常用數據

?? ???? ?.html / .htm:網頁文件(瀏覽器可打開)。

?? ???? ?.csv:逗號分隔的表格數據(Excel、記事本均可打開)。

?? ???? ?.json:存儲結構化數據的文件(常用于程序間數據交換)。

核心區分小技巧:

?? ???? ?如果你雙擊一個文件,它能“自己啟動并讓電腦做事”(比如打開軟件、運行游戲),大概率是程序文件(如.exe、.app)。

?? ???? ?如果你雙擊一個文件,必須先打開某個軟件才能顯示內容(比如用Word打開.docx,用播放器打開.mp4),那就是數據文件。

3. ?進制?件和?本?件

根據數據的組織形式,數據?件被稱為?本?件和?進制?件。
數據在內存中以?進制的形式存儲,如果不加轉換的輸出到外存的?件中,就是?進制?件。
如果要求在外存上以ASCII碼的形式存儲,則需要在存儲前轉換。以ASCII字符的形式存儲的?件就是?本?件。
?個數據在?件中是怎么存儲的呢?
字符?律以ASCII形式存儲,數值型數據既可以?ASCII形式存儲,也可以使??進制形式存儲。
如有整數10000,如果以ASCII碼的形式輸出到磁盤,則磁盤中占?5個字節(每個字符?個字節),??進制形式輸出,則在磁盤上只占4個字節
#include <stdio.h>
int main()
{int a = 10000;FILE* pf = fopen("test.txt", "wb");fwrite(&a, 4, 1, pf);//?進制的形式寫到?件中fclose(pf);pf = NULL;return 0;}

ps:二進制文件本身的內容就不是文字,用文本工具打開自然會是亂碼

ps:就是說二進制的程序文件可以在源文件下用二進制編輯器的打開方式去實現。

3.1? 這邊用二進制編譯器輸出時為啥沒有ox?

ox 并不是二進制或十六進制數據本身的一部分,它只是人類為了區分進制而加上的 '標記'。

4. 文件的打開和關閉

4.1 流和標準流

4.1.1 流
我們程序的數據需要輸出到各種外部設備,也需要從外部設備獲取數據,不同的外部設備的輸?輸出操作各不相同,為了?便程序員對各種設備進??便的操作,我們抽象出了流的概念,我們可以把流想象成流淌著字符的河。
C程序針對?件、畫?、鍵盤等的數據輸?輸出操作都是通過流操作的。
?般情況下,我們要想向流?寫數據,或者從流中讀取數據,都是要打開流,然后操作。
4.1.2 標準流
那為什么我們從鍵盤輸?數據,向屏幕上輸出數據,并沒有打開流呢?
那是因為C語?程序在啟動的時候,默認打開了3個流:
  1. stdin - 標準輸?流,在?多數的環境中從鍵盤輸?,scanf函數就是從標準輸?流中讀取數據。
  2. stdout - 標準輸出流,?多數的環境中輸出?顯?器界?,printf函數就是將信息輸出到標準輸出流中。
  3. stderr - 標準錯誤流,?多數環境中輸出到顯?器界?。
這是默認打開了這三個流,我們使?scanf、printf等函數就可以直接進?輸?輸出操作的。
stdin、stdout、stderr 三個流的類型是: FILE * ,通常稱為?件指針。
C語?中,就是通過 FILE* 的?件指針來維護流的各種操作的。
4.1.3??為什么和 FILE*(文件指針)有關?

在C語言里,所有“流”(包括標準流、你自己打開的文件)都用 FILE* 類型的指針來表示,這個指針就像“管道的閥門”——通過它操作流里的數據。

?? ???? ?標準流對應的 FILE* 指針是系統預先定義好的:stdin(標準輸入)、stdout(標準輸出)、stderr(標準錯誤)。

?? ???? ?你自己用 fopen 打開的文件(比如 fopen("a.txt", "r")),得到的也是 FILE* 指針,本質上和標準流的指針是同一類東西,只是指向的“管道”不同(一個是默認的屏幕/鍵盤,一個是你指定的文件)。

4.2 件指針

緩沖?件系統中,關鍵的概念是“?件類型指針”,簡稱“?件指針”。
每個被使?的?件都在內存中開辟了?個相應的?件信息區,?來存放?件的相關信息(如?件的名字,?件狀態及?件當前的位置等)。這些信息是保存在?個結構體變量中的。該結構體類型是由系統聲明的,取名 FILE.
例如,VS2013 編譯環境提供的 stdio.h 頭?件中有以下的?件類型申明:
struct _iobuf 
{
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};typedef struct _iobuf FILE;
不同的C編譯器的FILE類型包含的內容不完全相同,但是?同?異。
每當打開?個?件的時候,系統會根據?件的情況?動創建?個FILE結構的變量,并填充其中的信
息,使?者不必關?細節。
?般都是通過?個FILE的指針來維護這個FILE結構的變量,這樣使?起來更加?便。
下?我們可以創建?個FILE*的指針變量:
FILE* pf;//?件指針變量
定義pf是?個指向FILE類型數據的指針變量。可以使pf指向某個?件的?件信息區(是?個結構體變量)。通過該?件信息區中的信息就能夠訪問該?件。也就是說,通過?件指針變量能夠間接找到與它關聯的?件。
4.2.1 文件信息區

1. FILE結構體(你說的“文件信息區”)是程序和實際文件之間的“中間人”,程序通過它來操作文件內容。

打個比方:
你想往一個筆記本(實際文件)里寫東西,不會直接拿筆戳筆記本——得先翻開筆記本(打開文件),這時FILE結構體就像筆記本的“封面+書簽”:

?? ???? ?封面記錄著筆記本的位置(存在硬盤哪里)、能不能涂改(讀寫權限);

?? ???? ?書簽標記著當前寫到哪一行(文件當前位置)。

2. FILE結構體和“程序打開的某個文件”是一一綁定的,但不是和“程序本身”綁定。

舉個例子:
你寫了一個程序,同時打開了a.txt和b.txt兩個文件。這時程序里會有兩個FILE結構體指針:

?? ???? ?一個指向 a.txt 的FILE結構體(記錄a.txt的讀寫位置、權限等);

?? ???? ?另一個指向 b.txt 的FILE結構體(記錄b.txt的信息)。

這兩個結構體分別和 a.txt、b.txt綁定,程序通過它們分別操作兩個文件。

  • 當你關閉a.txt后,對應的FILE結構體就會被釋放,不再和任何文件綁定;
  • 而b.txt的結構體還在,直到你關閉它。
4.2.2 為啥說我們不需要特別關注到文件信息區的細節,而是通過它的指針形式找到它?

因為FILE結構體的內部細節對我們寫程序來說,屬于“沒必要知道的底層實現”,就像你用手機拍照時,不用知道攝像頭傳感器的具體工作原理,按快門就行。

1. FILE結構體的內部太復雜,且不統一

它里面可能包含幾十種信息(比如不同操作系統的FILE結構不一樣),但我們編程時只需要“打開/讀寫/關閉”這幾個動作。
就像你用遙控器開空調,不需要知道遙控器內部的電路板怎么設計——你只需要按“開”鍵,空調就工作了。
FILE指針就是那個“遙控器”,通過它調用fopen、fprintf等函數,就能完成操作,不用關心里面具體存了啥。

2. 用指針更安全、更方便

如果直接操作FILE結構體的內部數據(比如手動改它的“當前位置”),很容易改錯(比如改到負數位置),導致程序崩潰。
而C語言提供的函數(如fread、fseek)已經幫我們封裝好了這些操作,通過指針調用它們,相當于讓“專業工具”來處理,不容易出錯。

4.3 件的打開和關閉

?件在讀寫之前應該先打開?件,在使?結束之后應該關閉?件。
在編寫程序的時候,在打開?件的同時,都會返回?個FILE*的指針變量指向該?件,也相當于建?了指針和?件的關系。
ANSI C 規定使? fopen 函數來打開?件, fclose 來關閉?件。
 //打開?件FILE * fopen ( const char * filename, const char * mode );//關閉?件int fclose ( FILE * stream );
ps:這邊的文件路徑可以是windows上的任意文件,但是有兩個限制:
  1. 權限問題
  2. 路徑要對
mode表??件的打開模式,下?都是?件的打開模式:
文件使用方式含義如果指定文件不存在
“r”(只讀)為了輸入數據,打開一個已經存在的文本文件出錯
“w”(只寫)為了輸出數據,打開一個文本文件建立一個新的文件
“a”(追加)向文本文件尾添加數據建立一個新的文件
“rb”(只讀)為了輸入數據,打開一個二進制文件出錯
“wb”(只寫)為了輸出數據,打開一個二進制文件建立一個新的文件
“ab”(追加)向一個二進制文件尾添加數據建立一個新的文件
“r+”(讀寫)為了讀和寫,打開一個文本文件出錯
“w+”(讀寫)為了讀和寫,建議一個新的文件建立一個新的文件
“a+”(讀寫)打開一個文件,在文件尾進行讀寫建立一個新的文件
“rb+”(讀寫)為了讀和寫打開一個二進制文件出錯
“wb+”(讀寫)為了讀和寫,新建一個新的二進制文件建立一個新的文件
“ab+”(讀寫)打開一個二進制文件,在文件尾進行讀和寫建立一個新的文件
實例代碼:
/* fopen fclose example */
#include <stdio.h>
int main ()
{FILE * pFile;//打開?件pFile = fopen ("myfile.txt","w");//?件操作if (pFile!=NULL){fputs ("fopen example",pFile);//關閉?件fclose (pFile);}return 0;
}
4.3.1 文件路徑中起始點的解析

假設程序當前運行的目錄是 C:\A\B\C(即當前路徑在 C 文件夾里),來看兩個例子的區別:

例子1:.\\..\\..\\test.txt(1個 . + 2個 ..)

?? ???? ?解析步驟:

?? ?1.?? ?. → 從當前目錄 C:\A\B\C 開始

?? ?2.?? ?第一個 .. → 跳至上一級 C:\A\B

?? ?3.?? ?第二個 .. → 再跳至上一級 C:\A

?? ?4.?? ?最終找 test.txt → 實際路徑是 C:\A\test.txt

例子2:..\\..\\..\\test.txt(3個 ..)

?? ???? ?解析步驟:

?? ?1.?? ?從當前目錄 C:\A\B\C 開始(默認起點,無需 .)

?? ?2.?? ?第一個 .. → 跳至 C:\A\B

?? ?3.?? ?第二個 .. → 跳至 C:\A

?? ?4.?? ?第三個 .. → 再跳至 C:\(A 文件夾的上一級是根目錄 C:\)

?? ?5.?? ?最終找 test.txt → 實際路徑是 C:\test.txt

核心區別:

?? ???? ?例子1的路徑最終定位到 C:\A\test.txt(向上跳2級)

?? ???? ?例子2的路徑最終定位到 C:\test.txt(向上跳3級)

跳轉的層級不同,找到的文件位置自然不一樣~

4.3.2? 文件關閉和free有點相似

你混淆的點其實和「動態內存管理」「資源釋放」的共性與差異有關,這幾個概念確實容易串在一起,咱們分清楚核心邏輯就好了:

一、fclose() + 置空指針 與 free() + 置空指針的「異曲同工」之處

兩者本質都是 “釋放資源后避免誤用”,邏輯完全一致:

?? ???? ?free(p):釋放動態分配的內存(比如malloc申請的),但指針p仍保留原地址(變成野指針)。如果之后再用p讀寫,會訪問無效內存,導致錯誤。

?? ???? ?fclose(fp):釋放文件相關的系統資源(文件描述符、緩沖區等),但指針fp仍保留原地址(變成野指針)。如果之后再用fp操作文件,會訪問已回收的資源,導致錯誤。

所以兩者都需要在釋放后 手動置空指針(p = NULL; 或 fp = NULL;),目的是把“隱藏的錯誤”變成“明確的空指針錯誤”,方便調試。

二、為什么有人會誤認為“不置空會讓程序一直運行”?

可能和 “內存泄漏”的概念混淆了。動態內存管理中:

?? ???? ?如果用malloc申請了內存,卻忘記free,會導致 內存泄漏(系統內存被持續占用,無法回收)。

?? ???? ?對于長期運行的程序(比如服務器),內存泄漏累積到一定程度,可能導致系統內存不足,甚至程序崩潰(但不是“程序一直運行停不下來”,而是“運行中出問題”)。

但注意:

?? ???? ?內存泄漏的核心是“資源沒釋放”,和指針是否置空無關(哪怕free后沒置空,資源也已經釋放了,不會泄漏)。

?? ???? ?程序是否“停不下來”,只看代碼邏輯(比如while(1)死循環),和內存/文件資源是否釋放完全無關。

5. 件的順序讀寫

5.1 順序讀寫函數介紹

函數名功能適用于
fgetc字符輸入函數所有輸入流
fputc字符輸出函數所有輸出流
fgets文本行輸入函數所有輸入流
fputs文本行輸出函數所有輸出流
fscanf格式化輸入函數所有輸入流
fprintf格式化輸出函數所有輸出流
fread二進制輸入文件輸入流
fwrite二進制輸出文件輸出流
上?說的適?于所有輸?流?般指適?于標準輸?流和其他輸?流(如?件輸?流);所有輸出流?般指適?于標準輸出流和其他輸出流(如?件輸出流)。

5.2 對比?組函數:

scanf / fscanf / sscanf
printf / fprintf /? sprintf
5.2.1 scanf/fscanf/sscanf 的區別
  • scanf

功能:從標準輸入流(通常是鍵盤)讀取格式化數據。

原型int scanf(const char *format, ...);

示例

#include <stdio.h>int main() 
{int num;printf("請輸入一個整數: ");scanf("%d", &num);printf("你輸入的整數是: %d\n", num);return 0;
}

說明:程序運行時,會等待用戶通過鍵盤輸入數據,scanf?按照指定的格式?%d?讀取整數并存儲到變量?num?中。

  • fscanf

功能:從指定的文件流中讀取格式化數據。

原型int fscanf(FILE *stream, const char *format, ...);

示例

#include <stdio.h>int main() 
{FILE *fp;int num;fp = fopen("test.txt", "r");if (fp != NULL) {fscanf(fp, "%d", &num);printf("從文件中讀取的整數是: %d\n", num);fclose(fp);}return 0;
}
  • 說明:假設?test.txt?文件中存儲了一個整數,fscanf?從打開的文件流?fp?中,按照?%d?的格式讀取整數。它適用于從文件中讀取特定格式的數據,而不是從標準輸入讀取。

  • sscanf

功能:從字符串中讀取格式化數據。

原型int sscanf(const char *str, const char *format, ...);

示例

#include <stdio.h>int main() 
{char str[] = "123";int num;sscanf(str, "%d", &num);printf("從字符串中讀取的整數是: %d\n", num);return 0;
}
  • 說明sscanf?從給定的字符串?str?中,按照?%d?的格式解析出整數,并存儲到變量?num?中。它常用于從已有的字符串中提取特定格式的數據。
5.2.2? printf/fprintf/sprintf 的區別
  • printf

功能:將格式化的數據輸出到標準輸出流(通常是屏幕)。

原型int printf(const char *format, ...);

示例

#include <stdio.h>int main()
{int num = 10;printf("整數的值是: %d\n", num);return 0;
}
  • 說明printf?按照指定的格式?%d?將變量?num?的值輸出到屏幕上。

  • fprintf

功能:將格式化的數據輸出到指定的文件流中。

原型int fprintf(FILE *stream, const char *format, ...);

示例

#include <stdio.h>int main() 
{FILE *fp;int num = 20;fp = fopen("output.txt", "w");if (fp != NULL) {fprintf(fp, "整數的值是: %d\n", num);fclose(fp);}return 0;
}
  • 說明fprintf?將格式化的數據輸出到打開的文件流?fp?指向的文件中,這里是將包含整數?num?值的字符串寫入到?output.txt?文件。

  • sprintf

功能:將格式化的數據輸出到字符串中。

原型int sprintf(char *str, const char *format, ...);

示例

#include <stdio.h>int main() 
{char result[50];int num = 30;sprintf(result, "整數的值是: %d\n", num);printf("生成的字符串是: %s", result);return 0;
}

說明sprintf?按照指定的格式將數據寫入到字符數組?result?中,而不是直接輸出到屏幕或文件,之后可以對這個字符串進行進一步的處理,比如傳遞給其他函數 。

5.3 我對內存和文件的總結

假設寫了一個簡單的程序:

#include <stdio.h>
int main() 
{FILE *f = fopen("test.txt", "r"); // 用r模式打開文件int num_from_file;fscanf(f, "%d", &num_from_file); // 從文件讀數據(比如讀到123)fclose(f); // 關閉文件int num_from_keyboard;printf("請輸入一個數字:");scanf("%d", &num_from_keyboard); // 從鍵盤讀數據(比如輸入456)int result = num_from_file + num_from_keyboard; // 計算123+456printf("結果是:%d", result); // 屏幕顯示589return 0;
}

這里的關鍵:

?? ???? ?test.txt是外部文件,里面的123是“長期存儲”的(關了電腦也在)。

?? ???? ?程序運行時,會把123從文件讀到num_from_file這個變量里——這個變量存在內存里(臨時存儲,程序結束就消失了)。

?? ???? ?你從鍵盤輸入的456,會存在num_from_keyboard這個變量里——也在內存里,和文件沒關系。

總結來了:

  1. ?r模式的核心:只允許“讀取文件內容”,絕對不能改文件本身(文件里的123永遠是123)。
  2. ?程序的臨時變量:鍵盤輸入的數字、計算過程中的數據,都存在程序的內存里(像局部變量這種),是程序自己的“臨時工作區”,和被打開的文件沒關系。? ?
  3. 文件和程序是分開的:用r模式打開文件,只是“借用”文件的內容來用,程序后續的代碼(比如輸入、計算、顯示)都是服務于程序本身,不會碰文件一根毫毛。

簡單說:r模式下,文件是“只讀的素材”,程序是“處理素材的工具”,工具自己怎么折騰(臨時變量、輸入)都不影響素材本身。

6. 文件的隨機讀寫

6.1 fseek

根據?件指針的位置和偏移量來定位?件指針(?件內容的光標)。
int fseek ( FILE * stream, long int offset, int origin );

例子:

/* fseek example */
#include <stdio.h>
int main ()
{FILE * pFile;pFile = fopen ( "example.txt" , "wb" );fputs ( "This is an apple." , pFile );fseek ( pFile , 9 , SEEK_SET );fputs ( " sam" , pFile );fclose ( pFile );return 0;
}

例子2:

int fseek(FILE *stream, long offset, int origin);

參數說明

  • stream:文件指針(如?FILE *fp
  • offset:偏移量(字節數),可正可負(正數向后移,負數向前移)
  • origin:起始點(從哪里開始計算偏移),有 3 種取值:
    • SEEK_SET:從文件開頭開始(值為 0)
    • SEEK_CUR:從當前位置開始(值為 1)
    • SEEK_END:從文件末尾開始(值為 2)
// 假設文件已打開(fp)
fseek(fp, 100, SEEK_SET);  // 移動到文件第100個字節處(從開頭數)
fseek(fp, 50, SEEK_CUR);   // 從當前位置再向后移動50字節
fseek(fp, -30, SEEK_END);  // 從文件末尾向前移動30字節(定位到倒數第30字節)

6.2 ftell

返回?件指針相對于起始位置的偏移量
long int ftell ( FILE * stream );
例?:
/* ftell example : getting size of a file */
#include <stdio.h>
int main ()
{FILE * pFile;long size;pFile = fopen ("myfile.txt","rb");if (pFile==NULL)perror ("Error opening file");else{fseek (pFile, 0, SEEK_END); // non-portablesize=ftell (pFile);fclose (pFile);printf ("Size of myfile.txt: %ld bytes.\n",size);}
return 0;
}
  • 記錄當前位置,方便后續回到該位置
  • 計算文件大小(先定位到文件末尾,再用?ftell?獲取偏移量):
fseek(fp, 0, SEEK_END);  // 移動到文件末尾
long file_size = ftell(fp);  // 此時的偏移量就是文件總字節數

6.3 rewind

讓?件指針的位置回到?件的起始位置(簡化版的fseek)直接把文件指針移回文件開頭,等價于fseek(fp, 0, SEEK_SET)
void rewind ( FILE * stream );
例?:
/* rewind example */
#include <stdio.h>
int main ()
{int n;FILE * pFile;char buffer [27];pFile = fopen ("myfile.txt","w+");for ( n='A' ; n<='Z' ; n++)fputc ( n, pFile);rewind (pFile);fread (buffer,1,26,pFile);fclose (pFile);buffer[26]='\0';printf(buffer);return 0;
}

區別:rewind?沒有返回值,而?fseek?會返回 0(成功)或非 0(失敗),可以判斷操作是否成功。

6.4? 三者總結

  • fseek?是 "主動移動" 指針到任意位置
  • ftell?是 "查詢" 當前指針的位置
  • rewind?是 "快速復位" 指針到開頭

7. 文件讀取結束的判定

7.1 被錯誤使用的 feof

牢記:在?件讀取過程中,不能? feof 函數的返回值直接來判斷?件的是否結束。
feof 的作?是:當?件讀取結束的時候,判斷讀取結束的原因是否是:遇到?件尾結束。
1. ?本?件讀取是否結束,判斷返回值是否為 EOF ( fgetc ),或者 NULL ( fgets )
例如:
  • fgetc 判斷是否為 EOF .
  • fgets 判斷返回值是否為 NULL .
2. ?進制?件的讀取結束判斷,判斷返回值是否?于實際要讀的個數。
例如:
  • fread判斷返回值是否?于實際要讀的個數。
?本?件的例?:
#include <stdio.h>
#include <stdlib.h>int main(void)
{int c; // 注意:int,?char,要求處理EOFFILE* fp = fopen("test.txt", "r");if(!fp) {perror("File opening failed");return EXIT_FAILURE;}//fgetc 當讀取失敗的時候或者遇到?件結束的時候,都會返回EOFwhile ((c = fgetc(fp)) != EOF) // 標準C I/O讀取?件循環{putchar(c);}//判斷是什么原因結束的if (ferror(fp))puts("I/O error when reading");else if (feof(fp))puts("End of file reached successfully");fclose(fp);
}
?進制?件的例?:
#include <stdio.h>enum { SIZE = 5 };
int main(void)
{double a[SIZE] = {1.,2.,3.,4.,5.};FILE *fp = fopen("test.bin", "wb"); // 必須??進制模式fwrite(a, sizeof *a, SIZE, fp); // 寫 double 的數組fclose(fp);double b[SIZE];fp = fopen("test.bin","rb");size_t ret_code = fread(b, sizeof *b, SIZE, fp); // 讀 double 的數組if(ret_code == SIZE) {puts("Array read successfully, contents: ");for(int n = 0; n < SIZE; ++n)printf("%f ", b[n]);putchar('\n');} else  { // error handlingif (feof(fp))printf("Error reading test.bin: unexpected end of file\n");else if (ferror(fp)) {perror("Error reading test.bin");}}fclose(fp);
}

8. 文件緩沖區

ANSI C 標準采用“緩沖?件系統” 處理數據?件的,所謂緩沖?件系統是指系統?動地在內存中為程序中每?個正在使用的文件開辟?塊“?件緩沖區”。從內存向磁盤輸出數據會先送到內存中的緩沖區,裝滿緩沖區后才?起送到磁盤上。如果從磁盤向計算機讀?數據,則從磁盤?件中讀取數據輸?到內存緩沖區(充滿緩沖區),然后再從緩沖區逐個地將數據送到程序數據區(程序變量等)。
緩沖區的大小根據C編譯系統決定的。

8.1 考點一:緩沖區概念

通過一段簡單的文件寫入代碼,展示數據先寫入緩沖區,再寫入磁盤的過程,讓考生直觀感受緩沖區的存在。
#include <stdio.h>
#include <stdlib.h>int main() 
{FILE *fp;fp = fopen("test.txt", "w");if (fp == NULL) {perror("fopen");exit(EXIT_FAILURE);}// 向文件寫入數據,此時數據先寫入緩沖區fputs("Hello, File Buffer!", fp); // 程序結束前,緩沖區數據會自動寫入磁盤fclose(fp); return 0;
}
這?可以得出?個結論:
因為有緩沖區的存在,C語?在操作?件的時候,需要做刷新緩沖區或者在?件操作結束的時候關閉?件。
如果不做,可能導致讀寫?件的問題。
ps:說白了其實緩沖區是內存里的一塊區域,用來臨時存輸入或輸出的數據,能解決設備與 CPU 速度不匹配問題,提高運行效率 。
?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/90776.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/90776.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/90776.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SQL中的占位符、@Param注解和方法參數

代碼中出現的多個 username 和 password 代表不同層面的變量&#xff0c;具體含義如下&#xff08;按執行順序&#xff09;&#xff1a;### 1. Param("username") String username - 位置 &#xff1a;方法參數前的注解 - 作用 &#xff1a;- Param("username&q…

【SpringAI實戰】FunctionCalling實現企業級自定義智能客服

一、前言 二、實現效果 三、代碼實現 3.1 后端實現 3.2 前端實現 一、前言 Spring AI詳解&#xff1a;【Spring AI詳解】開啟Java生態的智能應用開發新時代(附不同功能的Spring AI實戰項目)-CSDN博客 二、實現效果 一個24小時在線的AI智能客服&#xff0c;可以給用戶提供培…

kotlin基礎【2】

變量類型var 和 val 的核心區別&#xff1a;關鍵字含義能否重新賦值類似概念&#xff08;Java&#xff09;varvariable&#xff08;可變變量&#xff09;可以普通變量&#xff08;無 final&#xff09;valvalue&#xff08;不可變變量&#xff09;不可以被 final 修飾的變量var…

【Spring AI】阿里云DashScope靈積模型

DashScope&#xff08;靈積模型&#xff09;是阿里云提供的大模型服務平臺&#xff0c;集成了阿里自研的 通義千問&#xff08;Qwen&#xff09;系列大語言模型&#xff08;LLM&#xff09;以及多模態模型&#xff0c;為企業與開發者提供開箱即用的 AI 能力。官網地址 https://…

Rust Web框架性能對比與實戰指南

Rust Actix Web Rust Web 框架的實用對比分析 以下是 Rust Web 框架的實用對比分析,涵蓋主要框架(如 Actix-web、Rocket、Warp、Axum 等)的常見使用場景示例,按功能分類整理: 基礎路由設置 Actix-web use actix_web::{get, App, HttpResponse, HttpServer, Responder}…

【解決vmware ubuntu不小心刪boot分區,進不去系統】

如果仍然提示 Unable to locate package testdisk&#xff0c;有可能是源中不包含該工具&#xff08;LiveCD 使用的是“最小環境”&#xff09;。 &#x1fa9b; 解決方法&#xff1a;切換到國內完整軟件源&#xff08;推薦&#xff09; 編輯 sources.list&#xff1a; sudo na…

04-netty基礎-Reactor三種模型

1 基本概念Reactor模型是一種事件驅動&#xff08;Event-Driven&#xff09;的設計模式&#xff0c;主要用于高效處理高并發、I/O密集型場景&#xff08;如網絡、服務器、分布式等&#xff09;。其核心思想就是集中管理事件&#xff0c;將I/O操作與業務邏輯解耦&#xff0c;避免…

踩坑無數!NFS服務從入門到放棄再到真香的血淚史

前言 說起NFS&#xff0c;我估計很多搞運維的兄弟都有一肚子話要說。這玩意兒吧&#xff0c;看起來簡單&#xff0c;用起來坑多&#xff0c;但是真正搞明白了又覺得挺香的。 前幾天有個朋友問我&#xff0c;說他們公司要搭建一個文件共享系統&#xff0c;問我推薦什么方案。我…

矩陣譜分解的證明及計算示例

1. 矩陣譜分解的條件矩陣的譜分解&#xff08;也稱為特征分解&#xff09;是將一個矩陣分解為一系列由其特征向量和特征值構成的矩陣乘積的過程。進行譜分解的前提條件包括&#xff1a;<1.> 矩陣是可對角化的&#xff08;Diagonalizable&#xff09;&#xff0c;即矩陣存…

Leetcode 07 java

169. 多數元素 給定一個大小為 n 的數組 nums &#xff0c;返回其中的多數元素。 多數元素是指在數組中出現次數 大于 ? n/2 ? 的元素。 你可以假設數組是非空的&#xff0c;并且給定的數組總是存在多數元素。 示例 1&#xff1a; 輸入&#xff1a;nums [3,2,3] 輸出&a…

CS231n-2017 Lecture6訓練神經網絡(一)筆記

本節主要講的是模型訓練時的算法設計數據預處理&#xff1a;關于數據預處理&#xff0c;我們有常用的3個符號&#xff0c;數據矩陣X&#xff0c;假設其尺寸是&#xff0c;N是數據樣本的數量&#xff0c;D是數據的維度均值減法(Mean subtraction)&#xff1a;是預處理最常用的形…

C++ 中實現 `Task::WhenAll` 和 `Task::WhenAny` 的兩種方案

&#x1f4da; C 中實現 Task::WhenAll 和 Task::WhenAny 的兩種方案 引用&#xff1a; 拈朵微笑的花 想一番人世變換 到頭來輸贏又何妨日與夜互消長 富與貴難久長 今早的容顏老於昨晚C 標準庫異步編程示例&#xff08;一&#xff09;C TAP&#xff08;基于任務的異步編程…

【學習】Codeforces Global Round 15 C. Maximize the Intersections

題意&#xff1a;給出一個圓&#xff0c;順時針排布1~2*n&#xff0c;已知連了k條邊&#xff0c;問這個圓最好情況下有多少個線的交點&#xff0c;要求線與線之間不能有重復的連接點&#xff0c;也就是每個點只能被一條線連接 思路&#xff1a; 1.考慮沒有線的時候&#xff0…

圖論:Dijkstra算法

昨天介紹了最小生成樹的兩個算法&#xff0c;最小生成樹的兩個算法旨在求解無向有權圖中的最小代價聯通圖的問題&#xff0c;那么對于有向有權圖&#xff0c;從起點到終點的最小花費代價問題就可以用 Dijkstra 算法來解決而且Dijkstra算法可以求出來從起始點開始到所有節點的最…

WPFC#超市管理系統(2)顧客管理、供應商管理、用戶管理

超市管理系統3. 顧客管理3.1 顧客新增3.2 DataGrid樣式3.3 顧客刪除3.4 顧客修改4. 供應商管理4.1 供應商管理主界面4.2 新增供應商4.3 修改供應商5. 用戶管理5.1 用戶管理主界面5.2 新增用戶5.3 修改用戶總結3. 顧客管理 在CustomerView.xaml使用命令綁定方式添加頁面加載Loa…

Windows本地部署DeepSeek

1、Ollama1、下載Ollama安裝包https://ollama.com/download&#xff08;如果下載很慢 可以直接找我拿安裝包&#xff09;2、使用命令行安裝打開cmd 將下載的安裝包OllamaSetup.exe 放到想要安裝的目錄下。&#xff08;如果直接雙擊&#xff0c;會裝到C盤&#xff09;例如想裝到…

基于Python的新聞爬蟲:實時追蹤行業動態

引言 在信息時代&#xff0c;行業動態瞬息萬變。金融從業者需要實時了解政策變化&#xff0c;科技公司需要跟蹤技術趨勢&#xff0c;市場營銷人員需要掌握競品動向。傳統的人工信息收集方式效率低下&#xff0c;難以滿足實時性需求。Python爬蟲技術為解決這一問題提供了高效方…

阿里視頻直播解決方案VS(MediaMTX + WebRTC) 流媒體解決方案

背景&#xff1a; 公司采購了新的攝像頭&#xff0c;通過rtsp或者rtmp推流到云平臺&#xff0c;云平臺內部進行轉碼處理&#xff0c;客戶端使用HLS或HTTP-FLV播放&#xff0c;移動App可能使用HLS或私有SDK&#xff0c;超低延時則采用WebRTC。 技術選型&#xff1a; RTSP&…

day33:零基礎學嵌入式之網絡——TCP并發服務器

一、服務器1.服務器分類單循環服務器&#xff1a;只能處理一個客戶端任務的服務器并發服務器&#xff1a;可同時處理多個客戶端任務的服務器二、TCP并發服務器的構建1.如何構建&#xff1f;&#xff08;1&#xff09;多進程&#xff08;每一次創建都非常耗時耗空間&#xff0c;…

VR全景制作的流程?VR全景制作可以用在哪些領域?

VR全景制作的流程&#xff1f;VR全景制作可以用在哪些領域&#xff1f;VR全景制作&#xff1a;流程、應用與未來虛擬現實&#xff08;VR&#xff09;全景制作正迅速改變我們的感官體驗&#xff0c;使我們能夠身臨其境地探索虛擬世界&#xff0c;享受沉浸式的奇妙感受。那么&…