C語(yǔ)言文件操作詳解
一、什么是文件
在程序設(shè)計(jì)中,我們一般談的文件有兩種:程序文件、數(shù)據(jù)文件。
程序文件:
包括源程序文件(后綴為.c ),目標(biāo)文件( windows環(huán)境后綴為.obj ) ,可執(zhí)行程序( windows環(huán)境后綴為.exe )。
數(shù)據(jù)文件:
文件的內(nèi)容不一定是程序,而是程序運(yùn)行時(shí)讀寫(xiě)的數(shù)據(jù),比如程序運(yùn)行需要從中讀取數(shù)據(jù)的文件
或者輸出內(nèi)容的文件。
數(shù)據(jù)文件又分為”文本文件“和”二級(jí)制文件“
二進(jìn)制文件:數(shù)據(jù)在內(nèi)存中以二進(jìn)制的形式存儲(chǔ),如果不加轉(zhuǎn)換的輸出到外存,這種文件我們是看不懂的是一堆亂七八糟的符號(hào),只有電腦才可以讀懂。
文本文件:如果要求在外存上以ASCII碼的形式存儲(chǔ),則需要在存儲(chǔ)前轉(zhuǎn)換。以ASCII字符的形式
存儲(chǔ)的文件就是文本文件。這種文件我們是看得懂的,例如我們?cè)谟浭卤究吹降摹弊帧啊弊帜浮啊睌?shù)字“,這樣的文件就是文本文件。
二、文件緩沖區(qū)
ANSIC采用”緩沖文件系統(tǒng)“來(lái)處理數(shù)據(jù)文件,系統(tǒng)會(huì)為每一個(gè)正在使用的文件開(kāi)辟一塊”文件緩沖區(qū)“。當(dāng)程序從內(nèi)存向磁盤(pán)輸出數(shù)據(jù)時(shí),會(huì)將數(shù)據(jù)先送到輸出緩沖區(qū)中,等輸出緩沖區(qū)滿(mǎn)了之后,才將數(shù)據(jù)一起送到磁盤(pán);當(dāng)程序從磁盤(pán)向內(nèi)存讀數(shù)據(jù)時(shí),數(shù)據(jù)會(huì)先被送到輸入緩沖區(qū),等輸入緩沖區(qū)滿(mǎn)了之后,才將數(shù)據(jù)一起送到磁盤(pán);另外程序結(jié)束時(shí),緩沖區(qū)的內(nèi)容也會(huì)被送到內(nèi)存或磁盤(pán)。
三、文件指針
每個(gè)被使用的文件都在內(nèi)存中開(kāi)辟了一個(gè)相應(yīng)的文件信息區(qū),用來(lái)存放文件的相關(guān)信息(如文件的
名字,文件狀態(tài)及文件當(dāng)前的位置等)。這些信息是保存在一個(gè)結(jié)構(gòu)體變量中的。該結(jié)構(gòu)體類(lèi)型是
由系統(tǒng)聲明的,取名FILE。
該結(jié)構(gòu)體聲明如下:
struct _iobuf {
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
typedef struct _iobuf FILE;
每當(dāng)打開(kāi)一個(gè)文件的時(shí)候,系統(tǒng)會(huì)根據(jù)文件的情況自動(dòng)創(chuàng)建一個(gè)FILE結(jié)構(gòu)的變量,我們就可以通
過(guò)創(chuàng)建一個(gè)FILE的指針來(lái)維護(hù)這個(gè)FILE結(jié)構(gòu)的變量。
FILE* pf;//文件指針變量
四、文件的打開(kāi)和關(guān)閉。
文件的打開(kāi)用fopen函數(shù),文件的關(guān)閉用fclose函數(shù)。
它們的原型如下:
FILE * fopen ( const char * filename, const char * mode );
int fclose ( FILE * stream );
filenname:這個(gè)參數(shù)填的是文件名
mode:這個(gè)參數(shù)代表要對(duì)文件進(jìn)行的操作
stream:這個(gè)參數(shù)代表指向要關(guān)閉的文件的指針。
文件的操作方式有:
“r”(只讀):程序從一個(gè)文本文件讀入數(shù)據(jù),如果指定文件不存在會(huì)出錯(cuò) 。
“w”(只寫(xiě)):程序向一個(gè)文本文件輸出數(shù)據(jù),如果指定文件不存在會(huì)建立一個(gè)新的文件。
“a”(追加): 向文本文件尾添加數(shù)據(jù) ,如果指定文件不存在會(huì)出錯(cuò)
“rb”(只讀): 程序從一個(gè)文件讀入數(shù)據(jù),只不過(guò)這個(gè)文件是二進(jìn)制文件,如果指定文件不存在會(huì)出錯(cuò) 。
“wb”(只寫(xiě)): 程序向一個(gè)文件輸出數(shù)據(jù),只不過(guò)這個(gè)文件是二進(jìn)制文件 ,如果指定文件不存在會(huì)建立一個(gè)新的文件
“ab”(追加): 向一個(gè)二進(jìn)制文件尾添加數(shù)據(jù),,如果指定文件不存在會(huì)出錯(cuò)
“r+”(讀寫(xiě)): 為了讀和寫(xiě),這個(gè)文件是文本文件,如果文件不存在會(huì)出錯(cuò)
“w+”(讀寫(xiě)): 為了讀和寫(xiě),如果文件不存在會(huì)建立一個(gè)新的文件
“a+”(讀寫(xiě)): 打開(kāi)一個(gè)文件,在文件尾進(jìn)行讀寫(xiě) ,如果文件不存在會(huì)建立一個(gè)新的文件
“rb+”(讀寫(xiě)) :為了讀和寫(xiě),打開(kāi)一個(gè)二進(jìn)制文件 ,如果文件不存在會(huì)出錯(cuò)
“wb+”(讀寫(xiě)) :為了讀和寫(xiě)一個(gè)二進(jìn)制文件 ,如果文件不存在會(huì)建立一個(gè)新的文件
“ab+”(讀寫(xiě)):在 二進(jìn)制文件尾進(jìn)行讀和寫(xiě) 如果文件不存在會(huì)建立一個(gè)新的文件
文件的讀寫(xiě)函數(shù)有(這些函數(shù)是順序讀寫(xiě)):
字符輸入函數(shù):fgetc
字符輸出函數(shù):fputc
文本行輸入函數(shù):fgets
文本行輸出函數(shù):fputs
格式化輸入函數(shù):fscanf
格式化輸出函數(shù):fprintf
二進(jìn)制輸入:fread
二進(jìn)制輸出:fwrite
下面我們用代碼來(lái)體會(huì):
int main()
{
//打開(kāi)文件
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
//如果沒(méi)有讀到,返回錯(cuò)誤信息。
perror("fopen");
return -1;
}
//讀文件
//
//關(guān)閉文件
fclose(pf);
pf = NULL;
return 0;
}
我們對(duì)data.txt,進(jìn)行”r“(讀)操作,因?yàn)楫?dāng)前文件夾下沒(méi)有創(chuàng)建這個(gè)文件,所以出錯(cuò)。
現(xiàn)在我們?cè)诋?dāng)前目錄下,創(chuàng)建一個(gè)diata.txt文件夾,并輸入字符"abcd",使用fgetc函數(shù)來(lái)讀取數(shù)據(jù),這個(gè)函數(shù)的作用是讀取一個(gè)字符后,指針往下一個(gè)字符走。
int main()
{
//打開(kāi)文件
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return -1;
}
//讀文件
char ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);
//關(guān)閉文件
fclose(pf);
pf = NULL;
return 0;
}
結(jié)果為:

這是因?yàn)閯倓傞_(kāi)始時(shí),pf指針首先指向首字符”a“,讀完字符”a“后,pf指針就往下一個(gè)字符走,指向了字符”b“,讀完”b“后,pf指針繼續(xù)往下一個(gè)字符走,指向了字符”c“。
現(xiàn)在使用fgetc函數(shù)來(lái)讀取數(shù)據(jù),這個(gè)函數(shù)的作用是讀取一個(gè)字符串
int main()
{
//打開(kāi)文件
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return -1;
}
//讀文件
char arr[20] = { 0 };
fgets(arr, 20, pf);
printf("%s", arr);
//關(guān)閉文件
fclose(pf);
pf = NULL;
return 0;
}
結(jié)果是:

這個(gè)代碼的意思是從pf指向的那個(gè)文件讀取20個(gè)字符,存到數(shù)組arr中,我們知道文件只有4個(gè)字符,所以當(dāng)文件不夠要被讀取字符數(shù),程序就只會(huì)把文件中的內(nèi)容讀完,而不會(huì)報(bào)錯(cuò)。
下面我們進(jìn)行”w“操作,并分別使用fputc、fputs函數(shù)
fputc函數(shù)
int main()
{
FILE* pf = fopen("test.txt", "w");
if (NULL == pf)
{
perror("fopen");
return -1;
}
//寫(xiě)文件
fputc('b', pf);
fputc('i', pf);
fputc('t', pf);
//關(guān)閉文件
fclose(pf);
pf = NULL;
return 0;
}
我們向test.txt文件進(jìn)行寫(xiě)操作,如果我們對(duì)一個(gè)文件進(jìn)行寫(xiě)操作,如果這個(gè)文件存在,且有內(nèi)容,寫(xiě)操作會(huì)將文件的內(nèi)容銷(xiāo)毀,重新寫(xiě)入目前我們要寫(xiě)的內(nèi)容。因?yàn)槲覀儺?dāng)前文件夾下沒(méi)有創(chuàng)建這樣的文件,所以程序自動(dòng)幫我們創(chuàng)建,我們使用fputs函數(shù),這個(gè)函數(shù)的作用是向文件寫(xiě)入一個(gè)字符,在這些代碼中,我們分別寫(xiě)了”b“、”i“、”t“這幾個(gè)字符


fputs函數(shù)
int main()
{
FILE* pf = fopen("test.txt", "w");
if (NULL == pf)
{
perror("fopen");
return -1;
}
//寫(xiě)文件
//寫(xiě)一行數(shù)據(jù)
fputs("hello world\n", pf);
fputs("hello bit\n", pf);
//關(guān)閉文件
fclose(pf);
pf = NULL;
}
fputs函數(shù)的作用是向文件輸出一個(gè)字符串。因?yàn)檫@個(gè)文件在之前已經(jīng)創(chuàng)建,且有字符”bit“,現(xiàn)在我們重新進(jìn)行寫(xiě)操作,字符”bit“會(huì)被銷(xiāo)毀,重新寫(xiě)入hello world、hello bit這兩個(gè)字符串。

fprintf函數(shù)
struct S
{
int n;
double d;
};
int main()
{
struct S s = { 100, 3.14 };
FILE* pf = fopen("data.txt", "w");
if (NULL == pf)
{
perror("fopen");
return -1;
}
//寫(xiě)文件
fprintf(pf, "%d %lf", s.n, s.d);
//關(guān)閉文件
fclose(pf);
pf = NULL;
}
fprintf函數(shù)的作用是向pf指向的那個(gè)文件輸出格式化字符(所謂的格式化就是類(lèi)似于代碼中"%d %lf"的格式),所以這個(gè)程序會(huì)向文件輸出”100“和”3.140000“.

fscanf函數(shù)
struct S
{
int n;
double d;
};
int main()
{
struct S s = { 0 };
FILE* pf = fopen("data.txt", "r");
if (NULL == pf)
{
perror("fopen");
return -1;
}
//讀文件
fscanf(pf, "%d %lf", &(s.n), &(s.d));
printf("%d %lf\n", s.n, s.d);
//關(guān)閉文件
fclose(pf);
pf = NULL;
}
fscanf函數(shù)的作用是從文件中讀取格式化數(shù)據(jù),存到內(nèi)存中,由是一個(gè)代碼只,文件中有”100“和”3.140000“這兩個(gè)數(shù)據(jù),所以這個(gè)程序會(huì)將這兩個(gè)數(shù)據(jù)讀到結(jié)構(gòu)體變量s中.

最后兩個(gè)函數(shù)使用方法與fgetc fputc fgets fputs函數(shù)類(lèi)似,我就不示例了,同學(xué)們自己來(lái)試試吧!!!!!
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Qt學(xué)習(xí)教程之對(duì)話(huà)框消失動(dòng)畫(huà)效果
這篇文章主要給大家介紹了關(guān)于Qt學(xué)習(xí)教程之對(duì)話(huà)框消失動(dòng)畫(huà)效果的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-07-07
C++ Opencv自寫(xiě)函數(shù)實(shí)現(xiàn)膨脹腐蝕處理技巧
這篇文章主要介紹了C++ Opencv 自寫(xiě)函數(shù)實(shí)現(xiàn)膨脹腐蝕處理,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-10-10
PyQt5實(shí)現(xiàn)滑動(dòng)開(kāi)關(guān)的示例詳解
這篇文章主要為大家詳細(xì)介紹了如何使用PyQt5實(shí)現(xiàn)滑動(dòng)開(kāi)關(guān)的效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-12-12
超詳細(xì)VScode調(diào)試教程tasks.json和launch.json的設(shè)置
vscode是一個(gè)輕量級(jí)的文本編輯器,但是它的擴(kuò)展插件可以讓他拓展成功能齊全的IDE,這其中就靠的是tasks.json和launch.json的配置,下面這篇文章主要給大家介紹了關(guān)于超詳細(xì)VScode調(diào)試教程tasks.json和launch.json設(shè)置的相關(guān)資料,需要的朋友可以參考下2022-10-10
實(shí)例講解C++編程中l(wèi)ambda表達(dá)式的使用
這篇文章主要介紹了C++編程中l(wèi)ambda表達(dá)式的使用實(shí)例,lambda表達(dá)式特性的引入在C++11中可謂千呼萬(wàn)喚始出來(lái),非常重要,需要的朋友可以參考下2016-01-01

