【C語言】—— 文件操作(上)
- 一、 為什么使用文件
- 二、 什么是文件
- 2.1、 程序文件
- 2.2、 數據文件
- 2.3、 文件名
- 2.4、二進制文件與文本文件
- 三、 文件的打開和關閉
- 3.1、流和標準流
- (1)流
- (2)標準流
- 3.2、文件指針
- 四、文件的打開和關閉
一、 為什么使用文件
??我們為什么要使用文件呢?回答這個問題之前,我們先來看一段代碼:
#include<stdio.h>int main()
{int n = 0;scanf("%d", &n);printf("%d\n", n);return 0;
}
??這段代碼創建了一個變量 n n n,當程序運行時,我們輸入一個值(比如說 10 )存在變量 n n n 中,當我們下一次運行程序時,這個10 不見了,它的值又恢復到 0,我們又得重新輸入一個值。
??原來,像 n n n 這樣的變量是在內存里創建的,當程序結束時,剛剛申請的 4 個字節又還給了操作系統,當程序再次運行時, n n n中的值依然是 0。
??因此,如果將數據存在內存中,當程序結束,下次再運行時,這個值就不見了,它無法持久化地保存起來。
??怎么辦呢?
??這時我們想,如果我們在電腦上創建了一個文件,文件中存這一個 10。這個文件是放在硬盤上的(比如C盤、E盤)。這即使把電腦關機,下次打開里面依然存的是 10。
??這是因為,當我們把數據放在文件中,即硬盤上時,這些數據會持久化地保存下來。而相對的,放在內存中數據只要程序退出,數據就丟失了。
??因此當我們想把數據持久化地保存下來時,就需要文件。
??
二、 什么是文件
??硬盤(磁盤)上的文件就是文件。
??但是在程序設計中,我們一般談的文件有兩種:程序文件
、數據文件
(從文件功能的角度分類)
??
2.1、 程序文件
??所謂的程序文件就是我們寫出來的代碼,程序文件包括源程序文件(后綴文 . c .c .c),目標文件( w i n d o w s windows windows 環境后綴為 . o b j .obj .obj),可執行程序( w i n d o w s windows windows環境后綴為 . e x e .exe .exe)
??
2.2、 數據文件
??什么是數據文件呢?當我們寫程序,從某一個文件中讀取數據;或者把一些數據寫到文件中
,這種文件就稱為數據文件。
??本章我們討論的內容主要是數據文件。
??在之前的學習中,我們所處理的輸入輸出都是以終端
為對象的,即:從終端的鍵盤輸入數據,運行結果顯示到顯示器(屏幕)上。
??其實有時候我們會把信息輸出到磁盤上,當需要的時候再從磁盤上把數據讀取到內存中使用,這里處理的就是磁盤上的文件
。
??
2.3、 文件名
??一個文件要有唯一標識,以便用戶識別和引用
??文件名包含 3 部分:文件路徑
+文件名主干
+文件后綴
??如:c:\code\test.txt
- c:\code\ 為文件路徑
- t e s t test test 為文件名主干
- t x t txt txt 為文件后綴
??
2.4、二進制文件與文本文件
??根據文件的組織形式,數據文件一般被稱為文本文件和二進制文件
??數據在內存中以二進制的形式存儲
,如果不加轉換
的輸出到外出文件中,就是二進制文件。
??前面曾提到的 . o b j .obj .obj文件就是一種 二進制文件,通過文本編輯器打開是一堆亂碼,我們是看不懂的
??
??如果要求在外存上以 A S C I I ASCII ASCII 碼的形式存儲,則需要再存儲前轉換。以 A S C I I ASCII ASCII 字符存儲的文件就是文本文件。
??
??那么一個數據在文件中是如何存儲的呢?
??字符
一律以 A S C I I ASCII ASCII 碼形式存儲,數值型數據
及可以用 A S C I I ASCII ASCII 碼形式存儲,也可以使用二進制形式存儲。
??什么意思呢?假設現在有一個整數 10000:
??如果以 A S C I I ASCII ASCII 碼的形式存儲,則磁盤中占用 5 個字節(一個字符一個字節):一個字符 ‘1’,四個字符 ‘0’
??如果以二進制的形式存儲,磁盤上只占4個字節(一個整型)
??
??而以 A S C I I ASCII ASCII 碼形式存儲則為文本文件
;以二進制形式存儲則為二進制文件
。
??
測試代碼:
#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;
}
??這段代碼可能有些看不懂,但是沒關系,我們只需知道其大致意思即可:這段代碼就是將 10000 以二進制的形式寫到文件中
??執行程序后,我們直接打開文件:
??
??我們再通過二進制的形式打開文件
VS上打開二進制文件的方法
?
10000 在二進制文件中
?
??那 10 和 27 又是什么意思呢?其實就是 0001 0000 和 0010 0111 的十六進制表示
,同時,因為是小端字節序存儲
,因此存儲時反過來的。
??
三、 文件的打開和關閉
3.1、流和標準流
(1)流
??我們程序的數據要輸出
到各種外部設備(屏幕、硬盤、U盤、網絡上),也需要從外部設備(鍵盤、文件、網絡上、U盤)獲取
數據,不同的外部設備的輸入輸出的操作各不相同,為了方便程序員對各種設備進行方便操作,我們抽象出 流 的概念,我們可以把流想象成流淌著數據的河
。
??沒有流,程序員就要學會如何從各種不同的設備上輸入輸出數據,而有了流,程序員只需知道如何將數據從流中取出和寫入流即可,至于流如何與外部設備之間進行交流,我們并不關心,這是C語言底層和操作系統要關系的事情。這樣大大簡化了程序員學習編程的難度
??C程序針對文件、畫面、鍵盤等的數據輸入輸出操作都是通過流
操作的。
??一般情況下,我們要想向流里寫數據,或者從流中讀取數據,都是要打開流,然后操作
。
??進行文件操作,打開文件其實就是打開流,然后再對流進行讀寫
?
(2)標準流
??那為什么我們從鍵盤輸入數據,向屏幕上輸出數據,并沒有打開流呢?
??那是因為C語言程序在啟動的時候,默認打開了 3 個流
:
- stdin(標準輸入流):在大多數的環境中
從鍵盤輸入
, s c a n f scanf scanf 函數就是從標準輸入流中讀取數據。 - stdout(標準輸出流):大多數的環境中
輸出至顯示器界面
, p r i n t f printf printf函數就是將信息輸出到標準輸出流中。 - stderr(標準錯誤流):大多數環境中輸出到
顯示器界面
。
??這是默認打開了的三個流,我們使用 s c a n f scanf scanf、 p r i n t f printf printf 等函數就可以直接進行輸入輸出操作
的。
?? s t d i n stdin stdin、 s t d o u t stdout stdout、 s t d e r r stderr stderr 三個流的類型是: F I L E FILE FILE* ,通常稱為文件指針。
??C語言中,就是通過 F I L E FILE FILE* 的文件指針來維護流的各種操作
的
??
3.2、文件指針
??在緩沖文件系統中,關鍵的概念是“文件類型指針”,簡稱 “文件指針”。
??
??每一個被使用的文件都在內存中開辟了一個相應的文件信息區
,用來存儲文件的相關信息
(如文件的名字,文件狀態及文件當前的位置等)。這些信息是保存在一個結構體變量
中的。該結構體類型是有系統聲明的,取名 F I L E FILE FILE。
??
??例如在VS2013編譯器環境提供的 s t d i o . h stdio.h stdio.h 頭文件中有以下的文件類型聲明:
struct _iobuf {char* _ptr;int _cnt;char* _base;int _flag;int _file;int _charbuf;int _bufsiz;char* _tmpfname;};typedef struct _iobuf FILE;
??
??不同的編譯器的 F I L E FILE FILE 類型包含的內容不完全相同,但是大同小異。
??每當打開一個文件的時候,系統會根據文件的情況自動創建一個FILE結構的變量,并填充其中的信息
,使用者不必關系細節。
??一般都是通過一個 F I L E FILE FILE 指針來維護這個FILE結構的變量,這樣使用起來更加方便。
??下面我們可以創建一個 F I L E FILE FILE *的指針變量
??
FILE* pf;
??
??定義 p f pf pf 是一個指向 F I L E FILE FILE 類型數據的指針變量。可以使 p f pf pf指針指向某個文件信息區
(是一個結構體變量)。通過該文件信息區中的信息就能夠訪問該文件。也就是說,通過文件指針變量能夠簡潔找到與它關聯的文件。
??
??
四、文件的打開和關閉
??文件在讀寫之前應該先打開文件,在使用結束之后應該關閉文件。
??在編寫程序的時候,在打開文件的同時,都會返回一個 FILE* 指針變量指向該文件
,也相當于建立了指針和文件的關系。
?? A N S I ANSI ANSI? C C C規定使用 f o p e n fopen fopen函數來打開文件, f c l o s e fclose fclose函數來關閉文件。
f o p e n fopen fopen 函數(打開文件)
?
- 如果文件打開
成功
,返回一個FILE* 指針
,打開失敗
則返回空指針
- f i l e n a m e filename filename 表示要打開的
文件名
,其應符合文件的命名規范,可以包含文件路徑 - m o d e mode mode 表示
文件的打開模式
,下面都是文件的打開模式
?
文件使用方式 | 含義 | 如果指定文件不存在 |
---|---|---|
“r” (只讀) | 為了輸入數據,打開一個已經存在的文本文件 | 出錯 |
“w” (只寫) | 為了輸入輸出數據,打開一個文本文件 | 建立一個新的文件 |
“a”(追加) | 向文本文件尾添加數據 | 建立一個新的文件 |
“rb”(只讀) | 為了輸入數據,打開一個二進制文件 | 出錯 |
“wb”(只寫) | 為了輸出數據,打開一個二進制文件 | 建立一個新的文件 |
“ab”(追加) | 向一個二進制文件尾添加數據 | 建立一個新的文件 |
“r+”(讀寫) | 為了讀和寫,打開一個新的文件 | 出錯 |
“w+”(讀寫) | 為了讀和寫,創建一個新的文件 | 建立一個新的文件 |
“a+”(讀寫) | 打開一個文件,在文件尾進行讀寫 | 建立一個新文件 |
“rb+”(讀寫) | 為了讀和寫,打開一個二進制文件 | 出錯 |
“wb+”(讀寫) | 為了讀和寫,創建一個新的二進制文件 | 建立一個新的文件 |
“ab+”(讀寫) | 打開一個未禁止文件,在文件尾進行讀和寫 | 建立一個新的文件 |
??注:“ w w w”(只寫)會將原文件的內容全部清空,再從第一位開始寫入數據;“a”(追加) 是從文件末尾開始追加
??
f c l o s e fclose fclose 函數(關閉文件)
??使用 f c l o s e fclose fclose 函數將文件關閉后,要將該文件指針置空(如 f r e e free free 函數一樣)
??
??
??可能有些小伙伴對輸入輸出的關系還有些糊涂,我們可以來看下面一張圖
??其實,究竟是輸入還是輸出,應該站在程序的角度分析:程序從外界獲取數據,是輸入;程序向外輸出數據,是輸出。
??
下面,我們先來嘗試打開和關閉一個文件
#include<stdio.h>int main()
{FILE* pf = NULL;//打開文件pf = fopen("test.txt", "r");//文件操作if (NULL == pf){perror("fopen fail");return 1;}//讀文件//關閉文件fclose(pf);pf = NULL;
}
- 前面曾提到,文件打開失敗時, f o p e n fopen fopen 函數會返回一個空指針,因此使用 f o p e n fopen fopen 函數打開一個文件,要對其返回值進行判斷。
- r e t u r n return return 1 :表示的是程序異常,提前結束程序,
正常結束時返回0
。 - 使用 f c l o s e fclose fclose 函數將文件關閉,別忘了將
指針置空
,如同 f r e e free free函數一樣。
??
??
未完待續······