一個(gè)文件要有一個(gè)唯一的標(biāo)識(shí),以便用戶(hù)識(shí)別和引用。
文件名包含3個(gè)部分:文件路徑 + 文件名主干 + 文件后綴
c:\code\test.txt
根據(jù)數(shù)據(jù)的組織形式,對(duì)于數(shù)據(jù)文件來(lái)說(shuō),一般分為二進(jìn)制文件和文本文件
二進(jìn)制文件
數(shù)據(jù)在內(nèi)存中以二進(jìn)制的形式存儲(chǔ)
文本文件
要求在外存上以ASCII碼的形式存儲(chǔ),則需要在存儲(chǔ)前轉(zhuǎn)換。
系統(tǒng)會(huì)自動(dòng)的在內(nèi)存中為程序中每一個(gè)正在使用的文件開(kāi)辟一塊“文件緩沖區(qū)”
從內(nèi)存向磁盤(pán)輸出數(shù)據(jù),會(huì)先送到內(nèi)存中的緩沖區(qū),裝滿(mǎn)緩沖區(qū)后才一起送到磁盤(pán)上。
從磁盤(pán)向計(jì)算機(jī)讀入數(shù)據(jù),則從磁盤(pán)文件中讀取數(shù)據(jù)到內(nèi)存緩沖區(qū),然后再?gòu)木彌_區(qū)逐個(gè)將數(shù)據(jù)送到程序數(shù)據(jù)區(qū)(程序變量等)
緩沖區(qū)的大小根據(jù)編譯系統(tǒng)確定
1.4 文件指針文件類(lèi)型指針:簡(jiǎn)稱(chēng)文件指針
每個(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
typdef struct _iobuf FILE
每當(dāng)打開(kāi)一個(gè)文件時(shí),系統(tǒng)會(huì)根據(jù)文件的情況,自動(dòng)創(chuàng)建一個(gè)FILE類(lèi)型的變量,并填充里面的信息,使用者不必關(guān)注細(xì)節(jié)。
一般都是通過(guò)一個(gè)FILE類(lèi)型的指針,來(lái)維護(hù)這個(gè)FILE結(jié)構(gòu)的變量,這樣使用起來(lái)會(huì)很方便。
創(chuàng)建一個(gè)FILE*的指針變量
FILE* pf; // 文件指針變量
也就是說(shuō),通過(guò)文件指針,能夠找到與它相關(guān)聯(lián)的文件。
2 文件的打開(kāi)和關(guān)閉在編寫(xiě)程序的時(shí)候,在打開(kāi)文件的同時(shí),都會(huì)返回一個(gè)FILE*的指針變量指向該文件,也相當(dāng)于建立了指針和文件的關(guān)系
FILE* fopen(const char* filename, const char* mode);
int flcose(FILE* stream);
文件的打開(kāi)方式有下面幾種
文件使用方式 | 含義 | 如果指定文件不存在 |
---|---|---|
“r”(只讀) | 為了輸入數(shù)據(jù),打開(kāi)一個(gè)已經(jīng)存在的文本文件 | 出錯(cuò) |
“w”(只寫(xiě)) | 為了輸出數(shù)據(jù),打開(kāi)一個(gè)文本 | 建立一個(gè)新文件 |
“a”(追加) | 向文本文件尾添加數(shù)據(jù) | 出錯(cuò) |
“rb”(只讀) | 為了輸入數(shù)據(jù),打開(kāi)一個(gè)二進(jìn)制文件 | 出錯(cuò) |
“wb”(只寫(xiě)) | 為了輸出數(shù)據(jù),打開(kāi)一個(gè)二進(jìn)制文件 | 建立一個(gè)新文件 |
“ab”(追加) | 向一個(gè)二進(jìn)制文件尾添加數(shù)據(jù) | 出錯(cuò) |
“r+”(讀寫(xiě)) | 為了讀和寫(xiě),打開(kāi)一個(gè)文本文件 | 出錯(cuò) |
“w+”(讀寫(xiě)) | 為了讀和寫(xiě),建立一個(gè)新的文件 | 建立一個(gè)新文件 |
“a+”(讀寫(xiě)) | 打開(kāi)一個(gè)文件,在文件尾進(jìn)行讀寫(xiě) | 建立一個(gè)新文件 |
“rb+”(讀寫(xiě)) | 為了讀和寫(xiě)打開(kāi)一個(gè)二進(jìn)制文件 | 出錯(cuò) |
“rw+”(讀寫(xiě)) | 為了讀和寫(xiě),新建一個(gè)二進(jìn)制文件 | 建立一個(gè)新文件 |
“ab+”(讀寫(xiě)) | 打開(kāi)一個(gè)二進(jìn)制文件,在文件尾進(jìn)行讀寫(xiě) | 建立一個(gè)新文件 |
在寫(xiě)文件名的時(shí)候,可以是相對(duì)路徑,也可以是絕對(duì)路徑
注意點(diǎn)
3 文件的順序讀寫(xiě)
w
如果存在文件會(huì)清空,如果文件不存在,就建立一個(gè)新文件。
功能 | 函數(shù)名 | 適用于 |
---|---|---|
字符輸入函數(shù) | fgetc | 所有輸入流 |
字符輸出函數(shù) | fputc | 所有輸出流 |
文本行輸入函數(shù) | fgets | 所有輸入流 |
文本上輸出函數(shù) | fputs | 所有輸出流 |
格式化輸入函數(shù) | fscanf | 所有輸入流 |
格式化輸出函數(shù) | fprintf | 所有輸出流 |
二進(jìn)制輸入 | fread | 文件 |
二進(jìn)制輸出 | fwrite | 文件 |
讀文件(字符輸入)*
int main()
{FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{// 打開(kāi)失敗
printf("%s\n",strerror(errno));
return 0;
}
// 打開(kāi)成功
// 讀文件
printf("%c ", fgetc(pf));
printf("%c ", fgetc(pf));
printf("%c ", fgetc(pf));
printf("%c ", fgetc(pf));
printf("%c ", fgetc(pf));
// 關(guān)閉文件
fclose(pf);
pf = NULL; // 相當(dāng)于free一樣
}
寫(xiě)文件(字符輸出)
int main()
{FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{// 打開(kāi)失敗
printf("%s\n",strerror(errno));
return 0;
}
// 打開(kāi)成功
// 寫(xiě)文件
fputc('h', pf);
fputc('e', pf);
fputc('l', pf);
fputc('l', pf);
fputc('o', pf);
// 關(guān)閉文件
fclose(pf);
pf = NULL; // 相當(dāng)于free一樣
}
小知識(shí)點(diǎn)?。?!
鍵盤(pán)和屏幕這兩個(gè)輸入輸出流
鍵盤(pán)和屏幕都是外部設(shè)備
這兩個(gè)是程序默認(rèn)打開(kāi)的兩個(gè)流設(shè)備
分別對(duì)應(yīng)著stdin/stdout/stderr
這三個(gè)流的類(lèi)型都是FILE*
也就是說(shuō),鍵盤(pán)其實(shí)就是對(duì)應(yīng)著stdin
屏幕對(duì)應(yīng)著stdout
因此我們可以這樣設(shè)計(jì)程序
// 因?yàn)?fgetc/foutc 可以處理所有的輸入輸出流,因此鍵盤(pán)和屏幕也可以處理
3.2 文本輸入輸出char* fgets(char *string, int n, FILE *stream);
string
:從stream讀的內(nèi)容,放到string中去。就是一個(gè)緩沖的字符數(shù)組(字符串)
n
:最多讀取多少個(gè)字符注意的是 string 在讀取之后,本身就有一個(gè)換行,這個(gè)換行本身就是文件里面的,只不過(guò)換行是空白的隱藏起來(lái)了。
讀文件
int main()
{char buf[1024] = {0};
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{printf("%s\n", strerror(errno));
return 0;
}
// 讀文件
fgets(buf,1024, pf);
printf("%s", buf);
// puts(buf); 如果這里使用 puts,puts天生就會(huì)在末尾加換行,會(huì)出現(xiàn)多個(gè)空行的情況
fgets(buf, 1024, pf);
printf("%s", buf);
fclose(pf);
pf = NULL;
return 0;
}
寫(xiě)文件
int fputs(const char* string, FILE * stream);
int main()
{char buf[1024] = {0};
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{printf("%s\n", strerror(errno));
return 0;
}
// 寫(xiě)文件
fputs("hello 你好\n", pf);
fputs("hello world", pf);
fclose(pf);
pf = NULL;
return 0;
}
操作鍵盤(pán)和屏幕讀取輸出一行
int main()
{char buf[1024];
fgets(buf,1024,stdin);// 從標(biāo)準(zhǔn)輸入流讀取
fputs(buf, stdout);// 輸出到標(biāo)準(zhǔn)輸出流
return 0;
}
這種寫(xiě)法相當(dāng)于
gets(buf); puts(buf);
int printf(const char* format [,argument]...);
// 其實(shí)這里默認(rèn)是針對(duì) stdout的
int fprintf(FILE* stream, const char* format[,argument]...);
除了比printf
多了一個(gè)文件流參數(shù)之外,其他都一樣。
其實(shí)printf
默認(rèn)是針對(duì)stdout
的,也就是說(shuō)它的流是stdout
fprintf輸出函數(shù) 寫(xiě)文件
struct S
{int n;
float score;
char arr[10];
};
int main()
{struct S s[2] = {{100, 3.14f, "hello" }, {200,8.88f,"world"} };
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{return 0;
}
// 格式化寫(xiě)文件
fprintf(pf, "%d %f %s\n", s[0].n, s[0].score, s[0].arr);
fprintf(pf, "%d %f %s\n", s[1].n, s[1].score, s[1].arr);
// 關(guān)閉
fclose(pf);
pf = NULL;
}
fscanf 輸出讀文件
struct S
{int n;
float score;
char arr[10];
};
int main()
{struct S s[2] = {0};
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{return 0;
}
// 格式化讀文件 -- 首先要設(shè)置好存這個(gè)數(shù)據(jù)的變量 或者 結(jié)構(gòu)體
// 一定注意到在 scanf時(shí),變量要用其地址來(lái)接收
fscanf(pf, "%d %f %s", &s[0].n, &s[0].score, s[0].arr);
printf( "%d %f %s", s[0].n, s[0].score, s[0].arr);
fscanf(pf, "%d %f %s", &s[1].n, &s[1].score, s[1].arr);
printf("%d %f %s", s[1].n, s[1].score, s[1].arr);
// 關(guān)閉
fclose(pf);
pf = NULL;
}
標(biāo)準(zhǔn)輸入輸出流中讀取
struct S
{int n;
float score;
char arr[10];
};
int main()
{struct S s[2] = {0};
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{return 0;
}
// 格式化讀文件 -- 首先要設(shè)置好存這個(gè)數(shù)據(jù)的變量 或者 結(jié)構(gòu)體
// 一定注意到在 scanf時(shí),變量要用其地址來(lái)接收
fscanf(stdin, "%d %f %s", &s[0].n, &s[0].score, s[0].arr);
fprintf(stdout, "%d %f %s", s[0].n, s[0].score, s[0].arr);
// 關(guān)閉
fclose(pf);
pf = NULL;
}
scanf/printf是針對(duì)標(biāo)準(zhǔn)輸入輸出流的格式化輸入輸出語(yǔ)句
fscanf/fprintf是針對(duì)所有輸入輸出流的格式化輸入輸出語(yǔ)句
sscanf/sprintf 是針對(duì)字符串的格式化輸入輸出,從字符串中讀,輸出到字符串中去
int main()
{struct S s = {100, 3.14f, "hello"};
struct S tmp = {0};
char buf[1024] = {0};
// 把格式化的數(shù)據(jù)轉(zhuǎn)換成字符串,存儲(chǔ)到buf
sprintf(buf, "%d %f %s", s.n, s.score, s.arr);
// 從buf中讀取格式化的數(shù)據(jù)到tmp中
sscanf(buf, "%d %f %s", &(tmp.n), &(tmp.float), tmp.arr);
}
3.4 二進(jìn)制輸入輸出把結(jié)構(gòu)體學(xué)生的信息存入到文件中去,怎么寫(xiě)呢?
size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream);
buffer: 要寫(xiě)的內(nèi)容
size:元素的大小
count:元素的個(gè)數(shù)
struct S
{char name[20];
int age;
double score;
};
int main()
{struct S s = {"張三", 20, 64.5};
FILE* pf = fopen("test.txt", "wb");
if (pf == NULL)
{return 0;
}
// 二進(jìn)制寫(xiě)文件
fwrite(&s, sizeof(struct S), 1, pf);
// 關(guān)閉
fclose(pf);
pf = NULL;
}
fread 讀二進(jìn)制文件
size_t fread(const void* buffer, size_t size, size_t count, FILE* stream);
int main()
{//struct S s = {"張三", 20, 64.5};
struct S tmp = {0};
FILE* pf = fopen("test.txt", "rb");
if (pf == NULL)
{return 0;
}
// 二進(jìn)制寫(xiě)文件
//fwrite(&s, sizeof(struct S), 1, pf);
// 二進(jìn)制讀文件
fread(&tmp, sizeof(struct S), 1, pf); // 二進(jìn)制讀的文件,直接讀給這么大的內(nèi)存空間
printf("%s %d %f\n", tmp.name, tmp.age, tmp.score);
// 關(guān)閉
fclose(pf);
pf = NULL;
}
4 文件的隨機(jī)讀寫(xiě)1、fseek
根據(jù)文件指針的位置和偏移量來(lái)定位文件指針
int fseek(FILE * stream, long int offset, int origin);
offset
:偏移量。單位是字節(jié)
- 正值代表向后偏移
- 負(fù)值代表向前偏移
origin
:文件指針的當(dāng)前位置
SEEK_CUR
:文件指針當(dāng)前位置SEEK_END
:文件末尾(在最后一個(gè)字符的后面,而不是最后一個(gè)字符)SEEK_SET
:文件起始位置
通過(guò)調(diào)整文件指針,以當(dāng)前位置為起點(diǎn),根據(jù)偏移量來(lái)調(diào)整。
int main()
{ FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{return 0;
}
// 定位文件指針
// 我們默認(rèn)的 test.txt 里面存放的數(shù)據(jù)是 abcdef
fseek(pf, 2, SEEK_CUR); // 從當(dāng)前位置向后偏移 2 字節(jié),就是從 c 開(kāi)始
//fseek(pf, 2, SEEK_CUR); 從末尾向前偏移 2 字節(jié),e
// 讀取文件
int ch = fgetc(pf);
printf("%c\n", ch); // c
// 關(guān)閉
fclose(pf);
pf = NULL;
}
2、ftell
返回文件指針相對(duì)于起始位置的偏移量
long int ftell(FILE* stream);
int main()
{ FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{return 0;
}
// 定位文件指針
// 我們默認(rèn)的 test.txt 里面存放的數(shù)據(jù)是 abcdef
fseek(pf, -2, SEEK_END);
int pos = ftell(pf);
printf("%d\n", pos); // 4
// 讀取文件
// 關(guān)閉
fclose(pf);
pf = NULL;
}
3、rewind
讓文件指針的位置回到文件的起始位置
void rewind(FILE* stream);
int ch = fgetc(pf);
printf("%c\n", ch);
rewind(pf);
printf("%c\n", ch); // 這里依然是a
5 文件結(jié)束判定
被錯(cuò)誤使用的feof在文件讀取過(guò)程中,不能用feof
函數(shù)的返回值直接用來(lái)判斷文件是否結(jié)束
這個(gè)是應(yīng)用于當(dāng)文件讀取結(jié)束的時(shí)候,判斷是讀取失敗結(jié)束,還是遇到文件尾結(jié)束
EOF
或者NULL
fgetc
判斷是否為EOFfgets
判斷是否為NULLfread
判斷返回值是否小于實(shí)際要讀的個(gè)數(shù)while((ch = fgetc(pf)) != EOF)
{putchar(ch);
}
if (ferror(pf)) // 判斷是否遇到錯(cuò)誤而退出
{printf("error\n");
}else if(feof(of)) // 判斷是否遇到 EOF而退出
{printf("end of file \n");
}
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧