柚子快報(bào)邀請(qǐng)碼778899分享:學(xué)習(xí) C語言——文件操作
柚子快報(bào)邀請(qǐng)碼778899分享:學(xué)習(xí) C語言——文件操作
在之前我們寫的程序中當(dāng)程序結(jié)束,內(nèi)存就被回收數(shù)據(jù)就丟失了,那么在計(jì)算機(jī)中的那些需要保存寫下的數(shù)據(jù)時(shí),只把數(shù)據(jù)寫到內(nèi)存當(dāng)中就無法一直保留,如果要將數(shù)據(jù)進(jìn)行持久化的保存這時(shí)就需要再將數(shù)據(jù)傳輸?shù)酱疟P(硬盤)的文件上。這本篇中我們就來了解文件是什么、有哪些類型的文件,以及學(xué)習(xí)在程序中實(shí)現(xiàn)文件的讀和寫,還有實(shí)現(xiàn)讀和寫相關(guān)的函數(shù),相信看完本篇的講解能對(duì)文件有一定的認(rèn)識(shí),加油吧?。?!
1.什么是文件?
磁盤(硬盤)上的文件是文件。 但是在程序設(shè)計(jì)中,我們一般談的文件有兩種:程序文件、數(shù)據(jù)文件(從文件功能的角度來分類的)。
1.1 程序文件
程序文件包括源程序文件(后綴為.c),目標(biāo)文件(windows環(huán)境后綴為.obj),可執(zhí)行程(windows環(huán)境后綴為.exe)。
1.2 數(shù)據(jù)文件
文件的內(nèi)容不一定是程序,而是程序運(yùn)行時(shí)讀寫的數(shù)據(jù),比如程序運(yùn)行需要從中讀取數(shù)據(jù)的文件,或者輸出內(nèi)容的文件。
在以前各篇所處理數(shù)據(jù)的輸入輸出都是以終端為對(duì)象的,即從終端的鍵盤輸?數(shù)據(jù),運(yùn)行結(jié)果顯示到顯示器上。其實(shí)有時(shí)候我們會(huì)把信息輸出到磁盤上,當(dāng)需要的時(shí)候再從磁盤上把數(shù)據(jù)讀取到內(nèi)存中使用,這里處理的就是磁盤上文件。
2.文件名
?個(gè)文件要有?個(gè)唯一的文件標(biāo)識(shí),以便用戶識(shí)別和引用文件名包含3個(gè)部分:1.文件路徑 2.文件主干名 3.文件后綴
例如:C:\Users\zhuohongze\Desktop\c-language\test_6_10(1).txt 在以上的文件名中也是由三部分組成的
3.二進(jìn)制文件和文本文件?
根據(jù)數(shù)據(jù)的組織形式,數(shù)據(jù)文件被稱為文本文件或者二進(jìn)制文件。數(shù)據(jù)在內(nèi)存中以?進(jìn)制的形式存儲(chǔ),如果不加轉(zhuǎn)換的輸出到外存的文件中,就是二進(jìn)制文件。如果要求在外存上以ASCII碼的形式存儲(chǔ),則需要在存儲(chǔ)前轉(zhuǎn)換。以ASCII字符的形式存儲(chǔ)的?件就是文本文件。 ?個(gè)數(shù)據(jù)在文件中是怎么存儲(chǔ)的呢? 字符?律以ASCII形式存儲(chǔ),數(shù)值型數(shù)據(jù)既可以用ASCII形式存儲(chǔ),也可以使用?進(jìn)制形式存儲(chǔ)。 如有整數(shù)10000,如果以ASCII碼的形式輸出到磁盤,則磁盤中占用5個(gè)字節(jié)(每個(gè)字符?個(gè)字節(jié)),而二進(jìn)制形式輸出,則在磁盤上只占4個(gè)字節(jié)。
?在二進(jìn)制文件的讀和寫將在以下的了解fwrite和fread函數(shù)時(shí)進(jìn)行細(xì)致的講解
4.文件的打開與關(guān)閉
4.1 流和標(biāo)準(zhǔn)流
4.1.1流
在學(xué)習(xí)文件的打開關(guān)閉前先要來了解流,在我們將數(shù)據(jù)傳到外部設(shè)備時(shí)或者要讀取外部設(shè)備的數(shù)據(jù),外部設(shè)備可能是光盤也可能是硬盤上的文件等等,但是不同的外部設(shè)備的輸入和輸出方式可能不同,這時(shí)我們要操作外部設(shè)備方法都不同,如果給每個(gè)外部設(shè)備都寫一個(gè)操作方法就會(huì)很繁瑣,為了方便程序員對(duì)各種設(shè)備進(jìn)行方便的操作,我們抽象出了流的概念,我們可以把流想象成流淌著字符的河。
有了流程序員就不需要了解外部設(shè)備是怎么操作的,只需要關(guān)注怎么樣操作流就可以了,而流怎么把數(shù)據(jù)給外部設(shè)備這種底層的東西就不需要關(guān)注了
C程序針對(duì)文件、畫?、鍵盤等的數(shù)據(jù)輸入輸出操作都是通過流操作的。 ?般情況下,我們要想向流?寫數(shù)據(jù),或者從流中讀取數(shù)據(jù),都是要先打開流,然后操作。?
4.1.2 標(biāo)準(zhǔn)流
那為什么我們從鍵盤輸入數(shù)據(jù),向屏幕上輸出數(shù)據(jù),并沒有打開流呢? 那是因?yàn)镃語?程序在啟動(dòng)的時(shí)候,默認(rèn)打開了3個(gè)流:
? stdin - 標(biāo)準(zhǔn)輸入流,在大多數(shù)的環(huán)境中從鍵盤輸入,scanf函數(shù)就是從標(biāo)準(zhǔn)輸入流中讀取數(shù)據(jù)。? stdout - 標(biāo)準(zhǔn)輸出流,大多數(shù)的環(huán)境中輸出至顯示器界面,printf函數(shù)就是將信息輸出到標(biāo)準(zhǔn)輸出流中。? stderr - 標(biāo)準(zhǔn)錯(cuò)誤流,大多數(shù)環(huán)境中輸出到顯示器界面。
編寫時(shí)程序默認(rèn)打開了這三個(gè)流,所以我們使用scanf、printf等函數(shù)就可以直接進(jìn)行輸入輸出操作的。
4.2 文件指針
緩沖文件系統(tǒng)中,關(guān)鍵的概念是“文件類型指針”,簡(jiǎn)稱“文件指針”。 每個(gè)被使用的文件都在內(nèi)存中開辟了?個(gè)相應(yīng)的?件信息區(qū),用來存放文件的相關(guān)信息(如文件的名字,文件狀態(tài)及文件當(dāng)前的位置等)。這些信息是保存在?個(gè)結(jié)構(gòu)體變量中的。該結(jié)構(gòu)體類型是由系統(tǒng)聲明的,取名 FILE
?例如,VS2013 編譯環(huán)境提供的 stdio.h 頭文件中有以下的文件類型申明:
struct _iobuf {
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
typedef struct _iobuf FILE;
這以上就可以看出FILE是對(duì)結(jié)構(gòu)體struct _iobuf的重命名 注意以上只是VS2013下的文件類型申明,不同的C編譯器的FILE類型包含的內(nèi)容不完全相同,但是大同小異
每當(dāng)打開?個(gè)文件的時(shí)候,系統(tǒng)會(huì)根據(jù)文件的情況自動(dòng)創(chuàng)建?個(gè)FILE結(jié)構(gòu)的變量,并填充其中的信 息,這在當(dāng)中是怎么將信息填入和填入的有哪些信息我們不必關(guān)注 所以這時(shí)就將文件信息區(qū)的地址放在指針變量里,所以就可以通過?個(gè)FILE的指針來維護(hù)這個(gè)FILE結(jié)構(gòu)的變量,例如就可以用FILE* p在以上提到的標(biāo)準(zhǔn)流stdin、stdout、stderr 三個(gè)流的類型也是: FILE *
例如可以創(chuàng)建?個(gè)FILE *pf的指針變量:可以使pf指向某個(gè)文件的文件信息區(qū)(是?個(gè)結(jié)構(gòu)體變 量)。通過該文件信息區(qū)中的信息就能夠訪問該文件。也就是說,通過文件指針變量能夠間接找到與它關(guān)聯(lián)的文件。
例如:
4.3 文件的打開和關(guān)閉?
文件在讀寫之前應(yīng)該先打開文件,在使用結(jié)束之后應(yīng)該關(guān)閉文件。
在編寫程序的時(shí)候,在打開文件的同時(shí),都會(huì)返回?個(gè)FILE*的指針變量指向該?件,也相當(dāng)于建立了指針和文件的關(guān)系。 ANSI C 規(guī)定使用?fopen 函數(shù)來打開文件, fclose 來關(guān)閉文件。
?在fopen中打開文件的方式:
?件使用方式含義如果指定文件不存在“r”(只讀)為了輸入數(shù)據(jù),打開?個(gè)已經(jīng)存在的?本?件出錯(cuò)“w”(只寫)為了輸出數(shù)據(jù),打開?個(gè)文本?件建??個(gè)新的?件“a”(追加)向?本?件尾添加數(shù)據(jù)建??個(gè)新的?件“rb”(只讀)為了輸?數(shù)據(jù),打開?個(gè)?進(jìn)制?件出錯(cuò)“wb”(只寫)為了輸出數(shù)據(jù),打開?個(gè)?進(jìn)制?件建??個(gè)新的?件“ab”(追加)向?個(gè)二進(jìn)制?件尾添加數(shù)據(jù)建??個(gè)新的?件“r+”(讀寫)為了讀和寫,打開?個(gè)?本?件出錯(cuò)“w+”(讀寫)為了讀和寫,建議?個(gè)新的?件建??個(gè)新的?件“a+”(讀寫)打開?個(gè)?件,在?件尾進(jìn)?讀寫建??個(gè)新的?件“rb+”(讀寫)為了讀和寫打開?個(gè)?進(jìn)制?件出錯(cuò)“wb+”(讀 寫)為了讀和寫,新建?個(gè)新的?進(jìn)制?件建??個(gè)新的?件“ab+”(讀 寫打開?個(gè)?進(jìn)制?件,在?件尾進(jìn)?讀和寫建??個(gè)新的?件
例如以下打開與關(guān)閉文件代碼
#include
int main()
{
//打開文件test.txt
FILE* pf=fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//進(jìn)行操作
//
//關(guān)閉文件
fclose(pf);
pf = NULL;
return 0;
}
注意:在打開文件時(shí),使用fopen時(shí)要判斷返回值是否是NULL,如果是就不能繼續(xù)進(jìn)行操作,需要在此跳出程序。同時(shí)在使用fclose關(guān)閉文件后要將文件指針置為空指針,從而避免該指針變?yōu)橐爸羔?/p>
5. 文件的順序讀寫?
5.1 順序讀寫函數(shù)介紹
1.fputc和fgetc
fputc
fputc的作用是將字符輸出到文件當(dāng)中,當(dāng)然在這當(dāng)中也是將字符先輸入到流里,之后的工作由流來實(shí)現(xiàn),在putc函數(shù)中的參數(shù)有兩個(gè)第一個(gè)是所要輸出的字符,第二個(gè)是要輸出對(duì)象的文件指針。該函數(shù)輸出成功后,返回值為所寫字符,如果發(fā)生寫入錯(cuò)誤,返回值就為EOF
注:在使用fputc時(shí)也是要先打開文件,同時(shí)必須以寫的方式打開,不能以讀的方式打開文件,否則程序會(huì)發(fā)生錯(cuò)誤?
以下是該函數(shù)的使用舉例
#include
int main()
{
//打開文件test.txt
FILE* pf=fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//進(jìn)行操作
for (int i = 'a'; i<= 'z'; i++)
{
fputc(i, pf);
}
//關(guān)閉文件
fclose(pf);
pf = NULL;
return 0;
}
fgetc?
fgetc的作用是將當(dāng)前指定流的內(nèi)部文件指向的字符返回,同時(shí)內(nèi)部文件位置指示器將前進(jìn)到下一個(gè)字符。該函數(shù)的參數(shù)就是要輸入對(duì)象的文件指針使用fgetc讀取文件成功后,就返回讀取的字符,讀取失敗或者讀取到文件的末尾就返回EOF注:在使用fgetc時(shí)也是要先打開文件,同時(shí)必須以讀的方式打開,不能以寫的方式打開文件,否則程序會(huì)發(fā)生錯(cuò)誤?
以下是該函數(shù)的使用舉例
#include
int main()
{
//打開文件test.txt
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//進(jìn)行操作
int ch = 0;
while ((ch=fgetc(pf)) != EOF)
{
printf("%c", ch);
}
//關(guān)閉文件
fclose(pf);
pf = NULL;
return 0;
}
2.fputs和fgets
fputs
fputs的作用是將字符串寫入文件指針相關(guān)聯(lián)的文件流中,在puts函數(shù)中的參數(shù)有兩個(gè)第一個(gè)是所要輸出的字符串,第二個(gè)是要輸出對(duì)象的文件指針。當(dāng)在使用fputs時(shí)輸出成功后返回值為非負(fù)值,輸出失敗后返回EOF,并設(shè)置錯(cuò)誤標(biāo)識(shí)
注:在使用fputs時(shí)也是要先打開文件,同時(shí)必須以寫的方式打開,不能以讀的方式打開文件,否則程序會(huì)發(fā)生錯(cuò)誤?
在使用該函數(shù)時(shí),若在輸出時(shí)未換行將下一次輸出字符串將在上一次的末尾開始輸入
以下是該函數(shù)的使用舉例
int main()
{
//打開文件test.txt
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//進(jìn)行操作
fputs("abcdef", pf);
fputs("hello", pf);
//關(guān)閉文件
fclose(pf);
pf = NULL;
return 0;
}
?fgets
?fgets的作用是從流中獲取字符串輸入到字符數(shù)組中,直到讀取 (num-1) 個(gè)字符或到達(dá)換行符或文件末尾,在pgets函數(shù)中的參數(shù)有三個(gè)第一個(gè)是所要輸入字符串的數(shù)組指針,第二個(gè)是輸入過程中最大拷貝字符個(gè)數(shù),第三個(gè)是要輸入對(duì)象的文件指針。若使用fgets成功后返回值為指針str,若失敗返回空指針NULL,同時(shí)設(shè)置錯(cuò)誤標(biāo)識(shí)
注:在使用fgets時(shí)也是要先打開文件,同時(shí)必須以讀的方式打開,不能以寫的方式打開文件,否則程序會(huì)發(fā)生錯(cuò)誤以下是該函數(shù)的使用舉例
include
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
char arr[20] = { 0 };
fgets(arr, 10, pf);
printf("%s", arr);
fclose(pf);
pf = NULL;
return 0;
}
當(dāng)在test.txt中寫入以下字符時(shí),調(diào)試以上代碼觀察fgets的輸入
在以上調(diào)試就可以看出當(dāng)文件當(dāng)中的第一行只有6個(gè)字符時(shí)最多就只能拷貝6個(gè)字符,不會(huì)再拷貝下一行的數(shù)據(jù) ?
3.fwrite和fread
fwrite
fwrte的作用是將數(shù)組ptr以二進(jìn)制的形式輸出到流中,數(shù)組中每個(gè)元素大小為size,元素個(gè)數(shù)為count ,fwrite中有三個(gè)參數(shù),第一個(gè)是數(shù)組的指針,第二個(gè)是數(shù)組中每個(gè)元素的大小,第三個(gè)是數(shù)組元素的個(gè)數(shù),最后一個(gè)是輸出的文件指針
該函數(shù)的返回值是成功寫入到文件當(dāng)中的元素個(gè)數(shù),但如果寫入個(gè)數(shù)與參數(shù)數(shù)組個(gè)數(shù)count不相等則該函數(shù)就無法實(shí)現(xiàn),且這時(shí)程序會(huì)設(shè)置錯(cuò)誤標(biāo)識(shí)
注:在使用fwrite時(shí)也是要先打開文件,同時(shí)必須以寫的方式打開,不能以讀的方式打開文件,否則程序會(huì)發(fā)生錯(cuò)誤?
在使用fwrite時(shí)打開文件的方式與之前用到的函數(shù)不同寫文件用到的時(shí)wb,例如以下代碼就是將數(shù)據(jù)以二進(jìn)制的形式寫入文件當(dāng)中
以下是該函數(shù)的使用舉例
struct S
{
char name[10];
int age;
double sorce
}s={"Lisi",18,82.5};
int main()
{
FILE* pf = fopen("test.txt", "wb");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fwrite(&s, sizeof(struct S), 1, pf);
fclose(pf);
pf = NULL;
return 0;
}
這時(shí)在以上代碼運(yùn)行后打開文件就會(huì)發(fā)現(xiàn)文件中存放的是二進(jìn)制數(shù)據(jù),直接打開文件就會(huì)出現(xiàn)亂碼
這時(shí)就需要了解在VS中打開二進(jìn)制的文件?
這時(shí)以二進(jìn)制方式打開data.txt就可以看到文件中存放的數(shù)據(jù)如下
?fread
fread的作用是將流中二進(jìn)制的數(shù)據(jù)讀取到數(shù)組ptr中,數(shù)組中每個(gè)元素大小為size,元素個(gè)數(shù)為count ,fread中有三個(gè)參數(shù),第一個(gè)是數(shù)組的指針,第二個(gè)是數(shù)組中每個(gè)元素的大小,第三個(gè)是數(shù)組元素的個(gè)數(shù),最后一個(gè)是輸出的文件指針
該函數(shù)的返回值是成功讀取到文件當(dāng)中的元素個(gè)數(shù),但如果讀取個(gè)數(shù)與參數(shù)數(shù)組個(gè)數(shù)count不相等則該函數(shù)就無法實(shí)現(xiàn),且這時(shí)程序會(huì)設(shè)置錯(cuò)誤標(biāo)識(shí)
注:在使用fwrite時(shí)也是要先打開文件,同時(shí)必須以讀的方式打開,不能以寫的方式打開文件,否則程序會(huì)發(fā)生錯(cuò)誤?
在使用fread時(shí)打開文件的方式與之前用到的函數(shù)不同讀文件用到的時(shí)rb,例如以下代碼就是文件中讀取到s中并將結(jié)果打印到屏幕上
include
struct S
{
char name[10];
int age;
double sorce;
}s = { 0 };
int main()
{
FILE* pf = fopen("test.txt", "rb");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fread(&s, sizeof(struct S), 1, pf);
printf("%s %d %lf", s.name, s.age, s.sorce);
fclose(pf);
pf = NULL;
return 0;
}
4.scanf/fscanf/sscanf/printf/fprintf/sprintf
在之前的學(xué)習(xí)中我們已經(jīng)了解了scanf與printf的使用方法,printf只能將數(shù)據(jù)輸出到屏幕當(dāng)中,scanf只能讀取鍵盤上輸入的數(shù)據(jù),使用如果要針對(duì)所有輸入,輸出流這兩個(gè)函數(shù)就不能實(shí)現(xiàn)功能了,這時(shí)就要用到fscanf與fprintf‘這兩個(gè)函數(shù)
1.fscanf和fprintf
fcanf
fscanf的作用是從流中讀取格式化的數(shù)據(jù),該函數(shù)相比scanf參數(shù)只多了一個(gè)文件指針,但fscanf能實(shí)現(xiàn)所有流輸入
該函數(shù)的返回值是讀取格式化數(shù)據(jù)的個(gè)數(shù),如果在讀取時(shí)發(fā)生讀取錯(cuò)誤或到達(dá)文件末尾則返回EOF,且這時(shí)程序會(huì)設(shè)置錯(cuò)誤標(biāo)識(shí)
以下是該函數(shù)的使用舉例
include
struct S
{
char name[10];
int age;
double sorce;
}s = {0};
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fscanf(pf, "%s %d %lf", s.name, &(s.age), &(s.sorce));
printf("%s %d %lf", s.name, s.age, s.sorce);
fclose(pf);
pf = NULL;
return 0;
}
如果先創(chuàng)建test.txt這個(gè)文檔并且輸入以下數(shù)據(jù)
以上代碼輸出結(jié)果如下所示
?fprintf
fprintf的作用是將格式化的數(shù)據(jù)輸出到流中,該函數(shù)相比printf參數(shù)只多了一個(gè)文件指針,但fprintf能實(shí)現(xiàn)所有流輸出
該函數(shù)的返回值是輸入格式化數(shù)據(jù)的個(gè)數(shù),如果在輸入時(shí)發(fā)生讀取錯(cuò)誤或到達(dá)文件末尾則返回EOF,且這時(shí)程序會(huì)設(shè)置錯(cuò)誤標(biāo)識(shí)
以下是該函數(shù)的使用舉例
include
struct S
{
char name[10];
int age;
double sorce;
}s={"Lisi",18,82.66};
int main()
{
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fprintf(pf,"%s %d %lf", s.name, s.age,s.sorce);
fclose(pf);
pf = NULL;
return 0;
}
以上代碼運(yùn)行完后test.txt文件內(nèi)寫入數(shù)據(jù)如下?
?
2.ssanf和sprintf?
sscanf
sscanf的作用是將是將字符串中的數(shù)據(jù)讀取到格式化數(shù)據(jù)當(dāng)中該函數(shù)的返回值是字符串輸入到格式化數(shù)據(jù)的個(gè)數(shù),如果在讀取時(shí)發(fā)生讀取錯(cuò)誤或到達(dá)文件末尾則返回EOF,且這時(shí)程序會(huì)設(shè)置錯(cuò)誤標(biāo)識(shí)
以下是該函數(shù)的使用舉例
include
struct S
{
char name[20];
int age;
double sorce;
}s = { 0 };
int main()
{
char* p = "Zhangshang 20 90.3 ";
sscanf(p, "%s %d %lf", s.name, &(s.age), &(s.sorce));
fprintf(stdout, "%s %d %lf", s.name, s.age, s.sorce);
return 0;
}
輸出結(jié)果如下?
sprintf
sprintf的作用是將是將格式化數(shù)據(jù)轉(zhuǎn)換為字符串該函數(shù)的返回值是格式化數(shù)據(jù)輸出到字符串中的個(gè)數(shù),如果在讀取時(shí)發(fā)生讀取錯(cuò)誤或到達(dá)文件末尾則返回EOF,且這時(shí)程序會(huì)設(shè)置錯(cuò)誤標(biāo)識(shí)
以下是該函數(shù)的使用舉例
include
struct S
{
char name[20];
int age;
double sorce;
}s = { "Zhangshang",20,90.3 };
int main()
{
char arr[100] = {0};
sprintf(arr, "%s %d %lf", s.name, s.age, s.sorce);
fprintf(stdout, "%s", arr);
return 0;
}
輸出結(jié)果如下?
?函數(shù)總結(jié)
函數(shù)名功能適用于fgetc字符輸入函數(shù)所有輸入流fputc字符輸出函數(shù)所有輸出流fgets文本行輸入函數(shù)所有輸入流fputs文本行輸出函數(shù)所有輸出流fread 二進(jìn)制輸入 文件輸入流fwrite二進(jìn)制輸出文件輸出流 fscanf 格式化輸入函數(shù)所有輸入流fprintf格式化輸出函數(shù)所有輸出流sscanf格式化輸入函數(shù)所有輸入流sprintf格式化輸出函數(shù)所有輸出流
6. 文件的隨機(jī)讀寫
6.1 fseek
fseek的作用是用來重新指定文件指針,根據(jù)?件指針的位置和偏移量來定位?件指針(文件內(nèi)容的光標(biāo))該函數(shù)的參數(shù)有三個(gè),第一個(gè)是文件指針,第二個(gè)是目標(biāo)位置相較起始位置的偏移量,第三是起始位置指針
該函數(shù)如果成功,該函數(shù)將返回零。否則,它將返回非零值。
其中起始位置有以下三種情況?
以下是該函數(shù)的使用舉例
include
int main()
{
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fputs("hello", pf);
fseek(pf, -4, SEEK_END);
fputs("xxx", pf);
fclose(pf);
pf = NULL;
return 0;
}
以上代碼先將hello輸入到test.txt文件當(dāng)中,再使用fseek使得光標(biāo)從o后跳到了h后,再在文件中輸入xxx這時(shí)2文件的ell就會(huì)被xxx替代,文件內(nèi)容就變?yōu)閔xxxo
6.2 ftell
ftell的作用是返回文件指針相對(duì)于起始位置的偏移量該函數(shù)的參數(shù)是文件指針ftell的返回值是返回位置指標(biāo)的當(dāng)前值
以下是該函數(shù)的使用舉例
include
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int ch = 0;
ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);
fseek(pf, 4, SEEK_SET);
printf("%c\n", fgetc(pf));
printf("%d", ftell(pf));
fclose(pf);
pf = NULL;
return 0;
}
?先在test.txt文件中寫入hello
輸出結(jié)果如下
6.3 rewind
rewind的作用是讓文件指針的位置回到文件的起始位置該函數(shù)的參數(shù)是文件指針該函數(shù)無返回值
以下是該函數(shù)的使用舉例
include
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int ch = 0;
ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);
rewind(pf);
printf("%d", ftell(pf));
fclose(pf);
pf = NULL;
return 0;
}
?輸出結(jié)果如下
7. 文件讀取結(jié)束的判定?
牢記:在文件讀取過程中,不能用feof函數(shù)的返回值直接來判斷文件的是否結(jié)束
feof 的作用是:當(dāng)文件讀取結(jié)束的時(shí)候,判斷是讀取結(jié)束的原因是否是:遇到文件尾結(jié)束。
1. 文本文件讀取是否結(jié)束,判斷返回值是否為 EOF ( fgetc ),或者 NULL ( fgets ) 例如:? fgetc 判斷是否為 EOF .? fgets 判斷返回值是否為 NULL .
2. 二進(jìn)制文件的讀取結(jié)束判斷,判斷返回值是否小于實(shí)際要讀的個(gè)數(shù)。 例如:? fread判斷返回值是否小于實(shí)際要讀的個(gè)數(shù)。
文本文件的例子:
#include
#include
int main(void)
{
int c; // 注意:int,?char,要求處理EOF
FILE* fp = fopen("test.txt", "r");
if(!fp) {
perror("File opening failed");
return EXIT_FAILURE;
}
//fgetc 當(dāng)讀取失敗的時(shí)候或者遇到?件結(jié)束的時(shí)候,都會(huì)返回EOF
while ((c = fgetc(fp)) != EOF) // 標(biāo)準(zhǔn)C I/O讀取?件循環(huán)
{
putchar(c);
}
//判斷是什么原因結(jié)束的
if (ferror(fp))
puts("I/O error when reading");
else if (feof(fp))
puts("End of file reached successfully");
fclose(fp);
}
二進(jìn)制文件的例子:?
#include
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 的數(shù)組
fclose(fp);
double b[SIZE];
fp = fopen("test.bin","rb");
size_t ret_code = fread(b, sizeof *b, SIZE, fp); // 讀 double 的數(shù)組
if(ret_code == SIZE) {
puts("Array read successfully, contents: ");
for(int n = 0; n < SIZE; ++n)
printf("%f ", b[n]);
putchar('\n');
} else { // error handling
if (feof(fp))
printf("Error reading test.bin: unexpected end of file\n");
else if (ferror(fp)) {
perror("Error reading test.bin");
}
}
fclose(fp);
}
8. 文件緩沖區(qū)?
ANSIC 標(biāo)準(zhǔn)采?“緩沖文件系統(tǒng)” 處理的數(shù)據(jù)文件的,所謂緩沖文件系統(tǒng)是指系統(tǒng)?動(dòng)地在內(nèi)存中為程序中每?個(gè)正在使用的?件開辟?塊“文件緩沖區(qū)”。從內(nèi)存向磁盤輸出數(shù)據(jù)會(huì)先送到內(nèi)存中的緩沖區(qū),裝滿緩沖區(qū)后才?起送到磁盤上。如果從磁盤向計(jì)算機(jī)讀入數(shù)據(jù),則從磁盤文件中讀取數(shù)據(jù)輸入到內(nèi)存緩沖區(qū)(充滿緩沖區(qū)),然后再從緩沖區(qū)逐個(gè)地將數(shù)據(jù)送到程序數(shù)據(jù)區(qū)(程序變量等)。緩沖區(qū)的大小根據(jù)C編譯系統(tǒng)決定的。
?
柚子快報(bào)邀請(qǐng)碼778899分享:學(xué)習(xí) C語言——文件操作
好文鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。