一.文件的打開與關閉
- 為了讀寫文件,我們需要用到定義在stdio.h這個標準庫頭文件中的一些函數(shù)結構
-
下面按順序列出我們打開一個文件,進行讀寫操作所必須遵循的一個流程
1.調用“文件打開”函數(shù)fopen,返回一個指向該文件的指針
2.檢測文件是否打開成功,通過第一步fopen的返回值(文件指針)來判斷,如果指針為NULL,則表示打開失敗,我們需要停止操作,并且返回一個錯誤
3.如果文件打開成功,就可以用stdio.h中的讀寫函數(shù)來讀寫文件
4.完成讀寫操作,關閉文件,調用“文件關閉”函數(shù)fclose
1.fopen:打開文件
//函數(shù)原型
FILE* fopen(const char* fileName,const char* openMode);
- fileName:文件名,字符串類型,不可變
- openMode:打開方式,表明我們打開文件之后要干什么
可用的openMode
- 函數(shù)返回值:FILE指針
2.fclose:關閉文件
//函數(shù)原型
int fclose(FILE* pointerOnFile);
- pointerOnFile:指向文件文件的指針
-
函數(shù)的返回值(int)有兩種情況:
1.0:當關閉操作成功時
2.EOF(一般是-1):如果關閉失敗 - 關閉這個文件,目的是為了釋放占用的文件指針
二.讀寫文件的不同方法
學習如何對文件進行讀出和寫入
1.對文件寫入
我們學習三個寫入的函數(shù)
- fputc:file put character,在文件中寫入一個字符
- fputs:file put string,在文件中寫入一個字符串
- fprint:在文件中寫入一個格式化過的字符串,用法與printf幾乎相同,只是多了一個文件指針
fputc
int fputc(int character, FILE*pointerOnFile);
- character:int型變量,表示要寫入的字符
- pointerOnFile:指向文件的指針
- 函數(shù)返回值int:如果寫入失敗,則為EOF,否則會是另一個值
示例:
//程序用于向test.txt寫入字符'A'
#include <stdio.h>
int main(int argc, const char* argv[]) {
FILE* file = NULL;
file = fopen("/Users/xulei/Desktop/test.txt", "w");
if (file == NULL) {
printf("error");
}
fputc('A', file);
fclose(file);
return 0;
}
運行之后,會在我所給的路徑(桌面)下,創(chuàng)建一個test.txt
test.txt
fputs
int fputs(const char* string, FILE* pointerOnFile);
- stringr:char型變量,表示要寫入的字符串
- pointerOnFile:指向文件的指針
- 函數(shù)返回值int:如果寫入失敗,則為EOF,否則會是另一個值
示例:
//程序用于向test.txt寫入字符串
#include <stdio.h>
int main(int argc, const char* argv[]) {
FILE* file = NULL;
file = fopen("/Users/xulei/Desktop/test1.txt", "w");
if (file == NULL) {
printf("error");
}
fputs("你好,朋友\n最近怎么樣", file);
fclose(file);
return 0;
}
運行之后,會在我所給的路徑(桌面)下,創(chuàng)建一個test1.txt
test1.txt
fprintf
int fprintf(FILE* stream, const char *format, ...);
不僅可以向文件寫入字符串,而且這個字符串可以有由我們來格式化
示例:
//程序用于向test.txt寫入字符串
#include <stdio.h>
int main(int argc, const char* argv[]) {
FILE* file = NULL;
int age = 0;
file = fopen("/Users/xulei/Desktop/test2.txt", "w");
if (file == NULL) {
printf("error");
}
printf("你幾歲了?\n");
scanf("%d",&age);
fprintf(file, "使用者年齡是%d歲\n",age);
fclose(file);
return 0;
}
//運行結果
你幾歲了?
2
Program ended with exit code: 0
運行之后,會在我所給的路徑(桌面)下,創(chuàng)建一個test2.txt
test2.txt
2.對文件讀出
我們學習三個讀出的函數(shù)
- fgetc:file get character,在文件中讀出一個字符
- fgets:file get string,在文件中讀出一個字符串
- fscanf:在文件中讀出一個格式化過的字符串,用法與scanf幾乎相同,scanf是從用戶輸入讀取,而fscanf是從文件讀取
fgetc
int fgetc(FILE*pointerOnFile);
- pointerOnFile:指向文件的指針
- 函數(shù)返回值int:函數(shù)返回值是讀到的字符,如果不能讀到字符,那會返回EOF
-
fgetc函數(shù)每讀入一個字符,這個虛擬的游標就移動這個一個字符長度,我們就可以用一個循環(huán)讀出所有的字符
示例:
#include <stdio.h>
int main(int argc, const char * argv[]) {
FILE* file = NULL;
int currentCharacter = 0;
file = fopen("/Users/xulei/Desktop/test2.txt", "r");
if (file == NULL) {
printf("error");
}
do {
currentCharacter = fgetc(file);//讀取一個字符
printf("%c",currentCharacter);//顯示讀取的字符
} while (currentCharacter != EOF);
printf("\n");
fclose(file);
return 0;
}
//運行結果
使用者年齡是2歲
\377
Program ended with exit code: 0
//\377,其實就是-1,也就是EOF,表示讀到末尾
/*
\是C語言的轉義字符的起始標識。
當\后面直接接數(shù)字的時候,會被處理成對應的8進制。
于是\377也就是8進制377對應的ascii碼值,將其轉為二進制為
3 = 11
7 =111
于是值為11 111 111
也就是16進制的0xff, 10進制值為255。
這個是單字節(jié)無符號數(shù)所能表示的最大值,作為有符號數(shù)時,值為-1
*/
fgets
char *fgets(char *string, int characterNumberToRead, FILE* pointerOnFile);
這個函數(shù)每次最多讀一行,因為它遇到第一個'\n'(換行符)會結束讀取
示例:
#include <stdio.h>
int main(int argc, const char * argv[]) {
FILE* file = NULL;
char string[1000] = " ";//保證數(shù)組足夠大
file = fopen("/Users/xulei/Desktop/test1.txt", "r");
if (file == NULL) {
printf("error");
}
while (fgets(string, 1000, file) != NULL) {//只要某一行不是空值就讀取它
printf("%s\n",string);
}
fclose(file);
return 0;
}
//運行結果
你好,朋友
最近怎么樣
Program ended with exit code: 0
fscanf
int fscanf(FILE* stream, const char *format, ...);
此函數(shù)原理和scanf是一樣的,負責從文件中讀取規(guī)定樣式的內容
示例:
#include <stdio.h>
int main(int argc, const char * argv[]) {
FILE* file = NULL;
int score[3] = {30,19,32,};
//文件寫入
file = fopen("/Users/xulei/Desktop/test3.txt", "w");
if (file == NULL) {
printf("error");
}
for (int i = 0; i < 3; i++) {
fputc(i, file);
}
fclose(file);
//文件讀取
file = fopen("/Users/xulei/Desktop/test3.txt", "r");
if (file == NULL) {
printf("error");
}
fscanf(file, "%d %d %d",&score[0],&score[1],&score[2]);
printf("%d %d %d",score[0],score[1],score[2]);
printf("\n");
fclose(file);
return 0;
}
//運行結果
30 19 32
Program ended with exit code: 0
三.在文件中移動
前面我們提到一個虛擬的游標,現(xiàn)在我們仔細學一下
每當我們打開一個文件時,實際上都存在一個游標,標識你當前在文件中所處的位置,可以類比我們編輯文本時的光標
三個與文件中游標移動有關的函數(shù):
- ftell:告訴目前在文件中那個位置
- fseek:移動文件中的游標到指定位置
- rewind:將游標重置到文件的開始位置
ftell
返回一個long型的整數(shù)值,表明目前游標所在位置
long ftell(FILE* pointerOnFile);
fseek
此函數(shù)能使游標在文件(pointerOnFile指針所指)中從位置(origin所指)開始移動一段距離(move所指)
int fseek(FILE* pointerOnFile, long move, int origin);
- move:可以是一個正整數(shù),表明向前移動;0,不移動;負整數(shù),表明回退
-
origin:它有三個取值
1.SEEK_SET:文件開始處
2.SEEK_CUR:游標當前所處位置
3.SEEK_END:文件末尾
例子:
fseek(file, 5, SEEK_SET);
//這行代碼將游標放置到距離文件開始處5個位置的地方。
fseek(file, -3, SEEK_CUR);
//這行代碼將游標放置到距離當前位置往后3個位置的地方
fseek(file, 0, SEEK_END);
//這行代碼將游標放置到文件末尾。
rewind
相當于使用fseek來使游標回到0的位置
void remind(FILE* pointerOnFile);
//相當于fseek(file,0,SEEK_SET);
四.文件的重命名和刪除
兩個簡單的函數(shù):
- rename:重命名一個文件
- remove:刪除一個文件
rename
int rename(const char *oldName, const char *newName);
如果函數(shù)執(zhí)行成功,則返回0,否則返回非0的int型值
示例:
int main(int argc, char *argv[]){
rename("test.txt", "renamed_test.txt");
return 0;
}
remove
int remove(const char *fileToRemove);
fileToRemove就是我們要刪除的文件名
示例:
int main(int argc, char *argv[]){
remove("test.txt");
return 0;
}
五.數(shù)據(jù)塊讀寫函數(shù)fread 和 fwrite
讀數(shù)據(jù)塊數(shù)據(jù)的格式: fread(buffer,size,count,fp);
寫數(shù)據(jù)塊數(shù)據(jù)的格式: fwrite(buffer,size,count,fp);
buffer -- 是一個指針,在fread函數(shù)中,它表示存放輸入數(shù)據(jù)的首地址。在fwrite函數(shù)中,它表示存放輸出數(shù)據(jù)的首地址。
size -- 表示數(shù)據(jù)庫的字節(jié)數(shù)
count -- 表示要讀寫的數(shù)據(jù)庫塊數(shù)
fp -- 表示文件指針
fread(fa,4,5,fp); --> 意義: 是從fp所指的文件中,每次讀4個字節(jié)(一個實數(shù))送入實數(shù)組fa中,連續(xù)5次,即讀5個實數(shù)到fa中



