作者主頁:?paper jie的博客_CSDN博客
本文作者:大家好,我是paper jie,感謝你閱讀本文,歡迎一建三連哦。
本文錄入于《系統(tǒng)解析C語言》專欄,本專欄是針對于大學生,編程小白精心打造的。筆者用重金(時間和精力)打造,將算法基礎(chǔ)知識一網(wǎng)打盡,希望可以幫到讀者們哦。
其他專欄:《算法詳解》《C語言》《C語言-語法篇》等
內(nèi)容分享:本期將對c語言文件操作進行詳細的講解
目錄
為什么需要使用文件
什么是文件
程序文件
數(shù)據(jù)文件
文件名
文件的打開和關(guān)閉
文件指針
文件的打開和關(guān)閉
?文件的順序讀寫
?fgetc和fputc
?fgets和fputs
fscanf,sscanf 和 fprintf,srpintf
fread和fwrite
文件的隨機讀寫
?fseek
ftell
rewind?
文本文件和二進制文件
文件讀取結(jié)束的判定
被錯誤使用的feof
文件緩沖區(qū)
為什么需要使用文件
在前面的結(jié)構(gòu)體文章中,我們可以用它寫一個通訊錄的程序,當通訊錄運行后,可以給通訊錄增加,刪除數(shù)據(jù),這個時候數(shù)據(jù)是存儲在內(nèi)存中的,當程序結(jié)束后,通訊錄里的數(shù)據(jù)就被還給操作系統(tǒng)了。這里就涉及到了我們的數(shù)據(jù)持久化的問題。我們把數(shù)據(jù)持久化一般有兩種方法:1 數(shù)據(jù)存放到磁盤中 2 數(shù)據(jù)存放到數(shù)據(jù)庫中。
使用文件我們就是可以將數(shù)據(jù)存放到電腦的磁盤上,使數(shù)據(jù)持久化。
什么是文件
磁盤上的文件就是文件。在程序設(shè)計中我們一般有兩種文件:程序文件和數(shù)據(jù)文件。
程序文件
它包括源程序文件(后綴為.c) 目標文件(Windows環(huán)境下后綴為obj)可執(zhí)行程序(windows環(huán)境下后綴為exe)
數(shù)據(jù)文件
文件的內(nèi)容不一定是程序,而是程序運行時讀寫的數(shù)據(jù),比如程序運行時需要從中讀取數(shù)據(jù)的文件,或者輸出內(nèi)容的文件。
文件名
一個文件有一個唯一的文件標識名(文件標識名就是文件名),以便用戶識別和引用,文件有三部分:文件路徑+文件主干+文件后綴。
例:D:\practice\test.txt
文件的打開和關(guān)閉
文件指針
緩沖文件系統(tǒng)中,關(guān)鍵的概念是“文件類型指針”,簡稱為 文件指針。
每個被使用的文件都在內(nèi)存中開辟了一個相應(yīng)的文件信息區(qū),用來存放文件的相關(guān)信息(比如:文件的名字,狀態(tài),當前的位置等)。這些信息都是保存在一個結(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;
不同的編譯器FILEL類型包含的內(nèi)容不完全相同,但是大同小異。每當打開一個文件,系統(tǒng)就會根據(jù)文件的情況自動創(chuàng)建一個FILE的結(jié)構(gòu)變量,并填充其中的信息,使用者不必關(guān)心細節(jié)。
一般都是通過這個FILE指針來維護這個FILE結(jié)構(gòu)的變量。
FILE* pf;//文件指針變量
定義pf是一個指向FILE類型數(shù)據(jù)的指針變量??梢酝ㄟ^pf指向某個文件的文件信息區(qū)。通過該文件信息區(qū)中的信息就能夠訪問到該文件。就是說:通過文件指針變量可以找到與它相關(guān)的文件。
文件的打開和關(guān)閉
文件在讀寫的時候是先打開文件,在使用后關(guān)閉文件
在編寫程序的時候,打開文件的時候,都會返回一個FILE*的指針變量指向該文件,也相當于建立了指針和文件的關(guān)系。
ANSIC規(guī)定使用fopen函數(shù)來打開文件,fclose來關(guān)閉文件。
//打開文件
FILE * fopen ( const char * filename, const char * mode );
//關(guān)閉文件
int fclose ( FILE * stream );
? ? ? ? ? ?文件使用方式 :? ? ? ? ? 含義:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?若文件不存在:
“r”(只讀)
|
為了輸入數(shù)據(jù),打開一個已經(jīng)存在的文本文件? | ?出錯 |
“w”(只寫) |
為了輸出數(shù)據(jù),打開一個文本文件
|
建立一個新的文件
|
“a”(追加) |
向文本文件尾添加數(shù)據(jù)
|
建立一個新的文件 |
“rb”(只讀) |
為了輸入數(shù)據(jù),打開一個二進制文件
|
出錯
|
wb”(只寫)
|
為了輸出數(shù)據(jù),打開一個二進制文件
|
建立一個新的文件
|
“ab”(追加)
|
向一個二進制文件尾添加數(shù)據(jù)
|
建立一個新的文件
|
“r+”(讀寫)
|
為了讀和寫,打開一個文本文件
|
出錯
|
“w+”(讀寫)
|
為了讀和寫,建議一個新的文件
|
建立一個新的文件
|
“a+”(讀寫)
|
打開一個文件,在文件尾進行讀寫
|
建立一個新的文件
|
“rb+”(讀寫)
|
為了讀和寫打開一個二進制文件
|
出錯
|
“wb+”(讀寫)
|
為了讀和寫,新建一個新的二進制文件
|
建立一個新的文件
|
“ab+”(讀寫)
|
打開一個二進制文件,在文件尾進行讀和寫
|
建立一個新的文件
|
栗子:
int main()
{
FILE* pf;
pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//寫文件
//關(guān)閉文件
fclose(pf);
return 0;
}
因為我的這個文件下沒有test.txt文件,它就報錯了
?文件的順序讀寫
?fgetc和fputc
int main()
{
FILE* pf;
pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int ch = fgetc(pf);
printf("%c ", ch);
ch = fgetc(pf);
printf("%c ", ch);
ch = fgetc(pf);
printf("%c ", ch);
fclose(pf);
pf = NULL;
return 0;
}
int main()
{
FILE* pf;
pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fputc('a', pf);
fputc('b', pf);
fputc('c', pf);
fclose(pf);
pf = NULL;
return 0;
}
?
?fgets和fputs
?
int main()
{
FILE* pf;
pf = fopen("test.txt", "w");
if (pf == NULL)
{
printf("open");
return 1;
}
fputs("aaaaaa", pf);
fputs("xxxxxxx", pf);
fclose(pf);
pf = NULL;
return 0;
}
?
注意:讀取文件在num-1結(jié)束或者遇到換行結(jié)束
int main()
{
FILE* pf;
pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
char arr[10] = { 0 };
fgets(arr, 10, pf);
printf("%s", arr);
fclose(pf);
pf = NULL;
return 0;
}
fscanf,sscanf 和 fprintf,srpintf
struct S
{
int a;
double b;
};
int main()
{
FILE* pf;
pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
struct S s = { 1, 3.15 };
fprintf(pf, "%d %f", s.a, s.b);
fclose(pf);
pf = NULL;
return 0;
}
?
struct S
{
int a;
double b;
};
int main()
{
FILE* pf;
pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
struct S s = { 0 };
fscanf(pf, "%d %lf", &(s.a), &(s.b) );
printf("%d %f", s.a, s.b);
fclose(pf);
pf = NULL;
return 0;
}
?
struct S
{
int a;
float b;
char ch[10];
};
int main()
{
struct S s = { 10, 19.5, "hello" };
char arr[100] = { 0 };
sprintf(arr, "%d %f %s", s.a, s.b, s.ch);
printf("%s", arr);
}
int main()
{
struct S s = { 10, 19.5, "hello" };
char arr[100] = { 0 };
sprintf(arr, "%d %f %s", s.a, s.b, s.ch);
//printf("%s", arr);
struct S tmp = { 0 };
sscanf(arr,"%d %f %s", &(tmp.a), &(tmp.b), &(tmp.ch));
printf("%d %f %s", tmp.a, tmp.b, tmp.ch);
}
?結(jié)論:
scanf:從標準輸入流中讀取格式化的數(shù)據(jù)
printf:從標準輸出流中寫格式化的數(shù)據(jù)
fscanf:適用于所有輸入流讀取格式化輸入函數(shù)
fprintf:適用于所有輸出流寫格式化輸出函數(shù)
sscanf:從字符串中讀取格式化的數(shù)據(jù)
sprintf:將格式化的數(shù)據(jù)轉(zhuǎn)化為字符串
fread和fwrite
#include <stdio.h>
struct S
{
int a;
double b;
char arr[10];
};
int main()
{
struct S s = { 1, 3.2, "hello" };
FILE* pf = fopen("test.txt", "wb");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fwrite(&s, sizeof(struct S), 1, pf);
return 0;
}
?
struct S
{
int a;
double b;
char arr[10];
};
int main()
{
struct S tmp = { 0 };
FILE* pf = fopen("test.txt", "rb");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fread(&tmp, sizeof(struct S), 1, pf);
printf("%d %f %s\n", tmp.a, tmp.b, tmp.arr);
return 0;
}
文件的隨機讀寫
?fseek
根據(jù)文件指針的位置和偏移量在定位指針
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fseek(pf, 2, SEEK_SET);
int ch = fgetc(pf);
printf("%c\n", ch);
return 0;
}
?
ftell
返回文件指針相對于起始位置的偏移量?
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fseek(pf, 2, SEEK_SET);
int ch = fgetc(pf);
//printf("%c\n", ch);
int pos = ftell(pf);
printf("%d\n", pos);
return 0;
}
rewind?
讓文件指針的位置回到文件的起始位置
文本文件和二進制文件
根據(jù)數(shù)據(jù)的具體方式,數(shù)據(jù)文件被稱為文本文件或者二進制文件。
?
文件讀取結(jié)束的判定
被錯誤使用的feof
文件在讀取的過程中,不能用feo函數(shù)的返回值直接用來判斷文件是否結(jié)束。
而是作用于文件讀取結(jié)束的時候,判斷是讀取失敗結(jié)束,還是遇到文件尾結(jié)束。返回的是非零的值則是讀取到了文件末尾,否則讀取失敗而結(jié)束。
判斷是否讀取結(jié)束可以用:
1文本文件是否讀取結(jié)束,判斷返回值是 否為EOF(fgetc),或者NULL(fgets)
2. 二進制文本的讀取結(jié)束判斷,判斷返回值是否小于實際要讀的個數(shù)
栗子:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
? ?int c; // 注意:int,非char,要求處理EOF
? ?FILE* fp = fopen("test.txt", "r");
? ?if(!fp) {
? ? ? ?perror("File opening failed");
? ? ? ?return EXIT_FAILURE;
? }
//fgetc 當讀取失敗的時候或者遇到文件結(jié)束的時候,都會返回EOF
? ?while ((c = fgetc(fp)) != EOF) // 標準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);
}
文件緩沖區(qū)
文章來源:http://www.zghlxwxcb.cn/news/detail-580118.html
?文章來源地址http://www.zghlxwxcb.cn/news/detail-580118.html
到了這里,關(guān)于一文帶你玩轉(zhuǎn)C語言文件操作的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!