【C語言】文件操作全解析

文章目錄

    • 一、為什么需要文件操作?
    • 二、認識文件:不止是磁盤上的存儲
      • 2.1 程序文件
      • 2.2 數據文件
      • 2.3 文件名的構成
    • 三、文本文件與二進制文件:數據的兩種形態
      • 3.1 存儲方式差異
      • 3.2 實例對比:整數10000的存儲
      • 3.3 二進制文件操作示例
    • 四、文件的打開與關閉:操作的開始與結束
      • 4.1 流的概念
      • 4.2 文件指針
      • 4.3 打開與關閉函數
      • 4.4 文件打開模式
      • 4.5 示例代碼
    • 五、文件的順序讀寫:按部就班的數據處理
      • 5.1 常用順序讀寫函數
      • 5.2 函數對比
    • 六、文件的隨機讀寫:自由定位數據位置
      • 6.1 fseek函數:定位文件指針
      • 6.2 ftell函數:獲取當前位置偏移量
      • 6.3 rewind函數:重置文件指針
    • 七、文件讀取結束的判定:正確識別結束條件
      • 7.1 feof函數的正確用法
      • 7.2 正確的判斷方式
    • 八、文件緩沖區:提升效率的中間層
      • 8.1 緩沖區演示
      • 8.2 重要結論
    • 總結

在C語言編程中,文件操作是實現數據持久化存儲的關鍵技術。無論是保存用戶數據、配置信息還是處理大量數據,都離不開文件操作。本文將詳細講解C語言文件操作的方方面面,從基本概念到實際應用,幫助你全面掌握這一重要技能。

一、為什么需要文件操作?

在程序運行過程中,我們處理的數據通常存儲在內存中。然而,內存具有臨時性的特點——當程序退出或計算機斷電時,內存中的數據會全部丟失。如果我們希望數據能夠長期保存,以便下次運行程序時繼續使用,就必須使用文件將數據存儲到磁盤等外部存儲設備中。

簡單來說,文件操作讓程序的數據擁有了"記憶"能力,是實現數據持久化的核心手段。

二、認識文件:不止是磁盤上的存儲

在C語言中,我們通常從功能角度將文件分為兩類:

2.1 程序文件

程序文件是用于構成程序本身的文件,包括:

  • 源程序文件(.c后綴)
  • 目標文件(Windows環境下為.obj后綴)
  • 可執行程序(Windows環境下為.exe后綴)

2.2 數據文件

數據文件是程序運行時讀寫的數據載體,比如:

  • 程序需要讀取的配置文件
  • 程序輸出的日志文件
  • 存儲用戶信息的數據庫文件

本文重點討論的是數據文件的操作。

2.3 文件名的構成

一個完整的文件名包含三個部分:

  • 文件路徑:指示文件在磁盤中的位置
  • 文件名主干:文件的核心標識
  • 文件后綴:指示文件類型

例如:c:\code\test.txt中,c:\code\是路徑,test是文件名主干,.txt是后綴。

三、文本文件與二進制文件:數據的兩種形態

根據數據的存儲形式,數據文件可分為文本文件和二進制文件,它們的區別如下:

3.1 存儲方式差異

  • 二進制文件:數據在內存中以二進制形式存儲,不加轉換直接輸出到外存
  • 文本文件:數據在存儲前被轉換為ASCII碼形式,以字符形式存儲

3.2 實例對比:整數10000的存儲

以整數10000為例:

  • 文本文件存儲:占用5個字節(每個字符一個字節),存儲內容是’1’,‘0’,‘0’,‘0’,'0’的ASCII碼
  • 二進制文件存儲:在VS2019環境下僅占用4個字節,直接存儲其二進制形式00000000 00000000 00100111 00010000

3.3 二進制文件操作示例

#include <stdio.h>
int main()
{int a = 10000;FILE* pf = fopen("test.txt", "wb");  // 以二進制寫入模式打開文件fwrite(&a, 4, 1, pf);  // 將a以二進制形式寫入文件fclose(pf);pf = NULL;return 0;
}

在VS中查看二進制文件時,需要使用二進制編輯器,10000會顯示為10270000

四、文件的打開與關閉:操作的開始與結束

4.1 流的概念

C語言通過"流"(stream)來操作各種外部設備(包括文件)。流可以想象成"流淌著字符的河",程序通過流與外部設備進行數據交換。

C程序啟動時會默認打開3個標準流:

  • stdin:標準輸入流(通常對應鍵盤)
  • stdout:標準輸出流(通常對應顯示器)
  • stderr:標準錯誤流(通常對應顯示器)

這就是為什么我們可以直接使用scanfprintf函數進行輸入輸出,而無需手動打開流。

4.2 文件指針

緩沖文件系統中,通過文件指針(FILE*類型)來管理文件。每個被打開的文件在內存中都有一個對應的文件信息區(結構體),存儲文件名、狀態、當前位置等信息,文件指針就指向這個結構體。

定義文件指針的方式:

FILE* pf;  // 聲明一個文件指針變量

4.3 打開與關閉函數

  • 打開文件:使用fopen函數

    FILE * fopen ( const char * filename, const char * mode );
    
  • 關閉文件:使用fclose函數

    int fclose ( FILE * stream );
    

4.4 文件打開模式

文件打開模式決定了對文件的操作權限,常見模式如下:

文件使用方式含義如果指定文件不存在
“r”(只讀)打開文本文件用于輸入出錯
“w”(只寫)打開文本文件用于輸出創建新文件
“a”(追加)向文本文件末尾添加數據創建新文件
“rb”(只讀)打開二進制文件用于輸入出錯
“wb”(只寫)打開二進制文件用于輸出創建新文件
“ab”(追加)向二進制文件末尾添加數據創建新文件
“r+”(讀寫)打開文本文件用于讀寫出錯
“w+”(讀寫)創建文本文件用于讀寫創建新文件
“a+”(讀寫)打開文本文件用于讀寫,從末尾開始創建新文件

4.5 示例代碼

#include <stdio.h>
int main ()
{FILE * pFile;// 打開文件pFile = fopen ("myfile.txt","w");// 文件操作if (pFile!=NULL){fputs ("fopen example",pFile);// 關閉文件fclose (pFile);}return 0;
}

五、文件的順序讀寫:按部就班的數據處理

順序讀寫是指從文件的開頭到結尾依次進行讀寫操作,C語言提供了一系列函數實現這一功能:

5.1 常用順序讀寫函數

函數名功能適用于
fgetc字符輸入函數所有輸入流
fputc字符輸出函數所有輸出流
fgets文本行輸入函數所有輸入流
fputs文本行輸出函數所有輸出流
fscanf格式化輸入函數所有輸入流
fprintf格式化輸出函數所有輸出流
fread二進制輸入文件
fwrite二進制輸出文件

5.2 函數對比

  • 輸入函數家族

    • scanf:從標準輸入流讀取格式化數據
    • fscanf:從指定輸入流讀取格式化數據
    • sscanf:從字符串讀取格式化數據
  • 輸出函數家族

    • printf:向標準輸出流輸出格式化數據
    • fprintf:向指定輸出流輸出格式化數據
    • sprintf:將格式化數據輸出到字符串

六、文件的隨機讀寫:自由定位數據位置

隨機讀寫允許程序直接定位到文件的任意位置進行操作,主要通過以下函數實現:

6.1 fseek函數:定位文件指針

根據文件指針的當前位置和偏移量來定位指針:

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

參數origin可以是:

  • SEEK_SET:從文件開頭開始計算
  • SEEK_CUR:從當前位置開始計算
  • SEEK_END:從文件末尾開始計算

示例:

#include <stdio.h>
int main ()
{FILE * pFile;pFile = fopen ( "example.txt" , "wb" );fputs ( "This is an apple." , pFile );fseek ( pFile , 9 , SEEK_SET );  // 定位到第10個字符位置fputs ( " sam" , pFile );  // 從該位置開始寫入fclose ( pFile );return 0;
}
// 最終文件內容為:"This is a sample."

6.2 ftell函數:獲取當前位置偏移量

返回文件指針相對于文件起始位置的偏移量:

long int ftell ( FILE * stream );

示例:計算文件大小

#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);  // 定位到文件末尾size=ftell (pFile);  // 獲取偏移量,即文件大小fclose (pFile);printf ("Size of myfile.txt: %ld bytes.\n",size);}return 0;
}

6.3 rewind函數:重置文件指針

將文件指針重新定位到文件開頭:

void rewind ( FILE * stream );

示例:

#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);  // 輸出ABCDEFGHIJKLMNOPQRSTUVWXYZreturn 0;
}

七、文件讀取結束的判定:正確識別結束條件

很多初學者會錯誤地使用feof函數來判斷文件是否結束,這是需要避免的。

7.1 feof函數的正確用法

feof函數的作用是:當文件讀取結束時,判斷結束的原因是否是"遇到文件尾"。它并不能直接用來判斷文件是否結束。

7.2 正確的判斷方式

  1. 文本文件

    • 使用fgetc時,判斷返回值是否為EOF
    • 使用fgets時,判斷返回值是否為NULL

    示例:

    #include <stdio.h>
    #include <stdlib.h>
    int main(void)
    {int c;  // 注意:必須是int類型,以處理EOFFILE* fp = fopen("test.txt", "r");if(!fp) {perror("File opening failed");return EXIT_FAILURE;}// fgetc讀取失敗或遇到文件結束時返回EOFwhile ((c = fgetc(fp)) != EOF)putchar(c);// 判斷結束原因if (ferror(fp))puts("I/O error when reading");else if (feof(fp))puts("End of file reached successfully");fclose(fp);
    }
    
  2. 二進制文件

    • 使用fread時,判斷返回值是否小于實際要讀取的個數

    示例:

    #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);  // 寫入數組fclose(fp);double b[SIZE];fp = fopen("test.bin","rb");size_t ret_code = fread(b, sizeof *b, SIZE, fp);  // 讀取數組if(ret_code == SIZE) {puts("Array read successfully, contents: ");for(int n = 0; n < SIZE; ++n) printf("%f ", b[n]);putchar('\n');} else {  // 錯誤處理if (feof(fp))printf("Error reading test.bin: unexpected end of file\n");else if (ferror(fp)) {perror("Error reading test.bin");}}fclose(fp);
    }
    

八、文件緩沖區:提升效率的中間層

ANSI C標準采用"緩沖文件系統",系統會自動為每個正在使用的文件在內存中開辟一塊"文件緩沖區":

  • 輸出數據時:先送到內存緩沖區,緩沖區滿后再一起寫入磁盤
  • 輸入數據時:先從磁盤讀取到緩沖區,再從緩沖區送到程序數據區

緩沖區的大小由C編譯系統決定。

8.1 緩沖區演示

#include <stdio.h>
#include <windows.h>  // VS2019 WIN11環境
int main()
{FILE* pf = fopen("test.txt", "w");fputs("abcdef", pf);  // 數據先存入輸出緩沖區printf("睡眠10秒-此時打開test.txt,文件無內容\n");Sleep(10000);printf("刷新緩沖區\n");fflush(pf);  // 手動刷新緩沖區,數據寫入磁盤printf("再睡眠10秒-此時打開test.txt,文件有內容\n");Sleep(10000);fclose(pf);  // 關閉文件時也會刷新緩沖區pf = NULL;return 0;
}

8.2 重要結論

由于緩沖區的存在,操作文件時必須注意:

  • 及時刷新緩沖區(使用fflush函數)
  • 操作結束后關閉文件(fclose會自動刷新緩沖區)

否則可能導致數據未能正確寫入文件,造成數據丟失或不一致。

總結

文件操作是C語言編程中的重要技能,掌握它可以讓你的程序具備數據持久化能力。本文介紹了文件的基本概念、類型劃分、打開關閉、順序讀寫、隨機讀寫、結束判定以及緩沖區機制等內容。

在實際編程中,要注意以下幾點:

  • 始終檢查文件是否成功打開
  • 操作完成后及時關閉文件
  • 正確判斷文件讀取結束的條件
  • 理解并合理利用緩沖區機制

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

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

相關文章

C結構體的幾種定義形式 + typedef結合使用的好處

struct 語句定義了一個包含多個成員的新的數據類型&#xff0c;struct 語句的格式如下&#xff1a; struct tag { member-list member-list member-list ... } variable-…

SPICE電容矩陣

SPICE電容矩陣: 如果有許多條傳輸線,就可以用下標來標記每一條線。例如,如果有5條線,就用1~5分別標記,依慣例把返回路徑導體標記為導線0。圖10.6給出了5條導線和一個公共返回平面的橫截面圖。首先研究電容器元件,下一節再討論電感器元件。 在這個線的集合中,每對導線之間…

【Java】棧和隊列

文章目錄1.棧1.1 棧的定義1.2 棧的使用1.3 棧的模擬實現2.隊列2.1 隊列的定義2.2 隊列的使用2.3 隊列的模擬實現3.循環隊列3.1 循環隊列的概念3.2 循環隊列判斷空和滿4.雙端隊列Deque1.棧 1.1 棧的定義 棧是一種特殊的線性表&#xff0c;其只允許在固定的一段進行數據的插入或…

【性能測試】---測試工具篇(jmeter)

目錄 1、安裝并啟動jemeter 2、重點組件 2.1、線程組&#xff1a; 2.2、HTTP取樣器?編輯 2.3、查看結果樹 2.4、HTTP請求默認值 2.5、HTTP信息頭管理器 2.6、JSON提取器 2.7、JSON斷言 2.8、同步定時器 2.9、CSV數據文件設置 2.10、HTTP Cookie管理器 3、測試報告…

機器學習(12):拉索回歸Lasso

- 拉索回歸可以將一些權重壓縮到零&#xff0c;從而實現特征選擇。這意味著模型最終可能只包含一部分特征。 - 適用于特征數量遠大于樣本數量的情況&#xff0c;或者當特征間存在相關性時&#xff0c;可以從中選擇最相關的特征。 - 拉索回歸產生的模型可能更簡單&#xff0c;因…

Redis持久化存儲

Redis持久化存儲詳解 一、核心持久化機制 Redis提供兩種主要持久化方式&#xff1a;RDB&#xff08;快照&#xff09; 和 AOF&#xff08;追加文件&#xff09;&#xff0c;以及兩者的混合模式。 RDB&#xff08;Redis Database&#xff09;快照持久化 工作原理 RDB通過創建數據…

python學智能算法(三十四)|SVM-KKT條件回顧

【1】引言 前序學習進程中&#xff0c;對軟邊界拉格朗日方程進行了初步構建。 其中約定了兩個拉格朗日乘子要非負&#xff0c;其本質是要滿足KKT條件。 今天就乘此次機會&#xff0c;在回顧一下KKT條件。 【2】定義 當問題無約束的時候&#xff0c;只要讓函數梯度為零&#…

【網絡基礎】計算機網絡發展背景及傳輸數據過程介紹

本文旨在幫助初學者建立起計算機網絡的基礎認知&#xff0c;從網絡的發展背景到網絡協議的分層模型&#xff0c;再到IP與MAC地址的基本概念&#xff0c;全面覆蓋第一階段學習重點。 &#x1f4cc; 本節重點 了解計算機網絡的發展背景&#xff0c;掌握局域網&#xff08;LAN&am…

阿里云-通義靈碼:解鎖云原生智能開發新能力,讓云開發更“靈”~

免責聲明&#xff1a;此篇文章所有內容皆是本人實驗&#xff0c;并非廣告推廣&#xff0c;并非抄襲&#xff0c;如有侵權&#xff0c;請聯系筆者。 每日一句 信念其實就是相信未來&#xff0c; 相信內在&#xff0c; 以及坦然美好的心境。 目錄 每日一句 一. 引言 二.通義…

lesson33:Python協程詳解:從原理到實戰的異步編程指南

目錄 一、協程核心概念&#xff1a;輕量級并發的本質 1.1 什么是協程&#xff1f; 1.2 協程與線程/進程的對比 二、協程工作原理&#xff1a;事件循環與協作式調度 2.1 事件循環&#xff08;Event Loop&#xff09;&#xff1a;協程的"調度中心" 2.2 協作式調度…

深入理解C++模板進階:非類型參數、特化與分離編譯

前言C模板是泛型編程的核心&#xff0c;它允許我們編寫與類型無關的代碼。在掌握了模板的基礎知識后&#xff0c;我們需要進一步了解模板的高級特性&#xff0c;以便更靈活地使用它們。本文將深入探討三個重要的模板進階主題&#xff1a;非類型模板參數、模板特化以及模板的分離…

使用winsw把SpringBoot項目注冊成window服務

目錄 一、使用winsw注冊 1.1、項目打jar包 1.2、下載winsw 1.3、把 WinSW.NET4.exe 重新命名 1.4、編寫m配置文件用于配置注冊信息 1.5、創建文件夾存放你的文件 1.6、安裝服務 1.7、啟動服務 1.8、卸載服務 1.8、停止服務 一、使用winsw注冊 1.1、項目打jar包 例如項目jar包名…

進階向:Python開發簡易QQ聊天機器人

數字化時代的聊天機器人應用在當今數字化時代&#xff0c;聊天機器人已經成為日常生活和商業活動中不可或缺的一部分。根據市場研究數據顯示&#xff0c;全球聊天機器人市場規模預計將在2026年達到102億美元&#xff0c;年復合增長率達到34.75%。這些智能助手正廣泛應用于以下場…

基于開源鏈動2+1模式AI智能名片S2B2C商城小程序的用戶留存策略研究

摘要&#xff1a;在數字化商業競爭白熱化的當下&#xff0c;用戶留存成為企業可持續發展的核心命題。本文聚焦開源鏈動21模式AI智能名片S2B2C商城小程序這一創新技術組合&#xff0c;通過分析其技術架構、模式創新與生態閉環的協同效應&#xff0c;揭示其在降低用戶決策成本、提…

單詞的劃分(動態規劃)

題目描述有一個很長的由小寫字母組成字符串。為了便于對這個字符串進行分析&#xff0c;需要將它劃分成若干個部分&#xff0c;每個部分稱為一個單詞。出于減少分析量的目的&#xff0c;我們希望劃分出的單詞數越少越好。你就是來完成這一劃分工作的。輸入第一行&#xff0c;一…

C語言學習筆記——文件

目錄1 文件的概念2 程序文件和數據文件3 二進制文件和文本文件4 流4.1 流的概念4.2 標準流5 文件信息區和文件指針6 處理文件的庫函數6.1 fopen6.2 fclose6.3 fgetc6.4 fputc6.5 fgets6.6 fputs6.7 fscanf6.8 fprintf6.9 fread6.10 fwrite6.11 fseek6.12 ftell6.13 rewind6.14 …

C++語法與面向對象特性(2)

一.inline函數1.inline的基本特性被inline修飾的函數被稱為內聯函數。inline函數設計的初衷是為了優化宏的功能&#xff0c;編譯器會在編譯階段對inline函數進行展開。然而需要注意的是&#xff0c;inline對于編譯器而言是一種建議&#xff0c;它通常會展開一些簡短的&#xff…

Linux中grep命令

Linux 中的 grep 用法詳解grep 是 Linux 中強大的文本搜索工具&#xff0c;用于在文件或輸入流中查找匹配指定模式的行。其基本語法為&#xff1a;grep [選項] "模式" [文件]核心功能基礎搜索在文件中查找包含特定字符串的行&#xff1a;grep "error" log.…

【遙感圖像入門】遙感中的“景”是什么意思?

在遙感成像中,“3景城市影像”和“5景城市影像”中的“景”是遙感數據的基本單位,通常指一次成像過程中獲取的獨立遙感影像塊。這一概念的具體含義需結合技術背景和應用場景理解: 一、“景”的技術定義 單次成像的獨立覆蓋區域 遙感平臺(如衛星、飛機)在特定時間和位置對…

Pytorch-07 如何快速把已經有的視覺模型權重扒拉過來為己所用

下載&#xff0c;保存&#xff0c;加載&#xff0c;使用模型權重 在這一節里面我們會過一遍對模型權重的常用操作&#xff0c;比如&#xff1a; 如何下載常用模型的預訓練權重如何下載常用模型的無訓練權重&#xff08;只下載網絡結構&#xff09;如何加載模型權重如何保存權…