打开文件 使用fopen
函数打开文件,第一个参数是文件的路径,第二个参数是文件的打开模式,如只读、写入、追加;如果文件打开成功,将返回一个文件指针,否则返回NULL
1 FILE *fopen (const char *filename, const char *mode) ;
如下代码以只写模式打开了E:\temp\
文件夹下的test.txt文件
1 2 3 String filePath = "E:\\temp\\test.txt" ; FILE* file = fopen(filePath, "w" );
文件的打开模式有以下
文件使用方式 含义 如果指定文件不存在 “r”(只读) 打开一个已有的文本文件,只允许读取 出错 “w”(只写) 打开一个文本文件(清空原有数据),只允许写入 建立一个新的文件 “a”(追加) 打开一个文本文件,用于追加写入 建立一个新的文件 “rb”(只读) 打开一个已有的二进制文件,只允许读取 出错 “wb”(只写) 打开一个二进制文件(清空原有数据),只允许写入 建立一个新的文件 “ab”(追加) 打开一个二进制文件,用于追加写入 建立一个新的文件 “r+”(读写) 打开一个已有文本文件,允许读取和写入 出错 “w+”(读写) 打开一个文本文件(清空原有数据),允许读取和写入 建立一个新的文件 “a+”(读写) 打开一个文本文件,用于读取和追加写入 建立一个新的文件 “rb+”(读写) 打开一个已有二进制文件,允许读取和写入 出错 “wb+”(读写) 打开一个二进制文件(清空原有数据),允许读取和写入 建立一个新的文件 “ab+”(读写) 打开一个二进制文件,用于读取和追加写入 建立一个新的文件
打开的文件在操作结束后一定要使用fclose
函数关闭
1 int fclose (FILE *stream) ;
写出文件 通过以下函数写出文件到本地
函数 作用 fputc()
向文件中写入一个字符 fputs()
向文件中写入一行字符串 fprintf()
按指定格式向文件中写入数据
fputc fputc()
用于将一个字符写入指定的文件流中;character
是要向文件流中写入的字符;stream
是指向文件流的FILE
类型的指针,它指定了要写入的文件;该函数返回值是写入的字符,如果发生错误,则返回EOF
,这是一个表示文件尾或错误的宏,其代表的值为-1
1 int fputc (int character, FILE *stream) ;
如下代码使用fputc
函数在本地文件中写下了26
个字母
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 typedef char * String;int main () { String filePath = "E:\\temp\\test.txt" ; FILE* file = fopen(filePath, "w" ); if (file != NULL ) { int a_c = 'a' ; for (int i = 0 ; i < 26 ; i++) { int cc = a_c + i; int result = fputc(cc, file); if (result != EOF) { printf ("result = %c\n" , result); } else { perror("文件写入失败" ); return 1 ; } } printf ("文件写入完毕\n" ); fclose(file); file = NULL ; } else { perror("文件打开失败" ); return 1 ; } return 0 ; }
fputs fputs()
用于将一个字符串写入到指定的文件流中;str
是向文件流中写入的字符串;stream
是指向文件流的FILE
类型的指针;如果写入成功,函数返回一个非负整数,发生错误则返回EOF
1 int fputs (const char *str, FILE *stream) ;
如下代码使用fputs
函数在本地文件中写下了一段字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 #define ARR_LENGTH 4 typedef char * String;int main () { String str_arr[ARR_LENGTH] = {"悟已往之不谏,\n" , "知来者之可追。\n" , "实迷途其未远,\n" , "觉今是而昨非。" }; String filePath = "E:\\temp\\test.txt" ; FILE* file = fopen(filePath, "w" ); if (file != NULL ) { for (int i = 0 ; i < ARR_LENGTH; i++) { int result = fputs (str_arr[i], file); if (result == EOF) { perror("文件写入失败" ); return 1 ; } } printf ("文件写入完毕\n" ); fclose(file); file = NULL ; } else { perror("文件打开失败" ); return 1 ; } return 0 ; }
fprintf fprintf()
函数用于将格式化后的数据写入到指定的文件流中,格式化方式与printf()
类似,stream
表示指向文件流的指针,format
是包含占位符的字符串,...
是可变参数,用以填充字符串中的占位符;如果数据成功写入,返回写入的字符数(非负整数),如果发生错误则返回负值
1 int fprintf (FILE *stream, const char *format, ...) ;
如下代码使用fprintf
函数在本地文件中写下了一段字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 #define ARR_LENGTH 3 typedef char * String;struct Scores { String name; int chinese; int math; int english; } scores_arr[ARR_LENGTH] = {"小红" , 100 , 80 , 70 , "小刚" , 80 , 98 , 100 , "小明" , 90 , 60 , 80 }; int main () { String filePath = "E:\\temp\\test.txt" ; FILE* file = fopen(filePath, "w" ); int char_sum = 0 ; if (file != NULL ) { for (int i = 0 ; i < ARR_LENGTH; i++) { int result = fprintf (file, "姓名:%s,数学:%d,英语:%d,语文:%d\n" , scores_arr[i].name, scores_arr[i].chinese, scores_arr[i].math, scores_arr[i].english); char_sum += result; if (result < 0 ) { perror("写入文件时发生错误" ); return 1 ; } } printf ("文件写入完毕,共计字符 %d 个\n" , char_sum); fclose(file); file = NULL ; } else { perror("文件打开失败" ); return 1 ; } return 0 ; }
读取文件 通过以下函数读取本地文件
函数 作用 fgetc()
从文件中读取一个字符 fgets()
从文件中读取一行字符串 fscanf()
按指定格式从文件中读取数据
fgetc fgetc()
函数用于从指定的文件流中读取一个字符,只有一个参数是指向文件流的指针,如果读取成功,返回值被读取的字符的ASCII
值,如果到达文件末尾或者发生错误,返回EOF
;可以使用feof
和ferror
函数来进一步检查是文件末尾还是发生了错误 文件指针会在每次调用fgetc
后移动到下一个字符位置
1 int fgetc (FILE *stream) ;
如下代码使用fgetc
函数将本地文件中的内容逐个字符读取,并储存至缓冲区输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 typedef char * String;int main () { String filePath = "E:\\temp\\test.txt" ; FILE* file = fopen(filePath, "r" ); if (file != NULL ) { int character; char buffer[1024 ] = {0 }; for (int i = 0 ; (character = fgetc(file)) != EOF; i++) { buffer[i] = (char )character; } if (feof(file)) { printf ("character = %s" , buffer); } else if (ferror(file)) { perror("发生了读取错误" ); return 1 ; } fclose(file); file = NULL ; } else { perror("文件打开失败" ); return 1 ; } return 0 ; }
fgets fgets()
函数用于从文件流中读取一行文本;str
存储从文件中读取的文本;size
代表要读取的最大字符数,限制fgets
函数从文件流中每次最多读取size-1
个字符(因为最后一个元素要储存\0
),直到遇到换行符\n
或文件结束符EOF
,并在字符数组的末尾添加一个\0
字符形成字符串;stream
代表要读取的文件流;该函数的返回值是成功读取的字符串的地址,如果读取到文件末尾 或者发生错误,返回NULL
文件指针会在每次调用fgets
后移动到读取的字符串的末尾
1 char *fgets (char *str, int size, FILE *stream) ;
如下代码展示了fgets
函数“每次读取一行”,由于读取的文件中一共有5
行内容,而fgets
函数换行符\n
或文件结束符EOF
将会结束本轮的内容读取,并且每行内容的字符没有超出fgets
第二个参数限制的字符范围,所以代码中循环语句经过5
次循环,把test.txt
中的内容读取完毕 如果把fgets
第二个参数限制的字符范围设置为8
,即每次从文件流中最多读取7
个字符,那么循环语句将经过10
次循环读取完毕test.txt
中的内容,因为文件中的每行内容都在7~14
的范围内
1 2 3 4 5 6 假设test.txt中的内容如下: First line Second line Third line Fourth line Fifth line
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 typedef char * String;int main () { String filePath = "E:\\temp\\test.txt" ; FILE* file = fopen(filePath, "r" ); if (file != NULL ) { char str[1024 ] = {0 }; for (int i = 1 ; fgets(str, sizeof (str), file) ; i++) { printf ("第 %d 轮读取 = %s\n" , i, str); } fclose(file); file = NULL ; } else { perror("文件打开失败" ); return 1 ; } return 0 ; }
如下代码使用fgets
函数将本地文件中的内容逐行读取,并储存至缓冲区输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 typedef char * String;int main () { String filePath = "E:\\temp\\test.txt" ; FILE* file = fopen(filePath, "r" ); if (file != NULL ) { char str[1024 ] = {0 }; char buffer[1024 * 100 ] = {0 }; while (fgets(str, sizeof (str), file) != NULL ) { strcat (buffer, str); } printf ("buffer = %s\n" , buffer); fclose(file); file = NULL ; } else { perror("文件打开失败" ); return 1 ; } return 0 ; }
fscanf fscanf()
函数用于从文件中读取格式化输入,格式化方式与scanf()
类似;stream
表示要读取的文件流;format
表示格式化字符串;...
是可变参数列表,用于接收按照format
字符串指定格式读取的数据;该函数返回成功读取和匹配的参数个数,如果到达文件末尾或发生读取错误,则返回EOF
文件指针会在每次调用fscanf
后根据成功读取的数据大小移动
1 int fscanf (FILE *stream, const char *format, ...) ;
fscanf
函数在读取数据时以空白字符(包括空格、制表符和换行符)作为分隔符,如果想要读取多行数据,可以使用循环来多次调用;如下代码从指定文件中读取每一条符合格式要求的数据
1 2 3 4 假设test.txt中的内容如下: 姓名:小红,数学:100,英语:80,语文:70 姓名:小刚,数学:80,英语:98,语文:100 姓名:小明,数学:90,英语:60,语文:80
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 typedef char * String;int main () { String filePath = "E:\\temp\\test.txt" ; FILE* file = fopen(filePath, "r" ); if (file != NULL ) { char name[1024 ] = {0 }; int chinese = 0 , math = 0 , english = 0 ; while (fscanf (file, "姓名:%[^,],数学:%d,英语:%d,语文:%d\n" , name, &math, &english, &chinese) != EOF) { printf ("学生姓名:%s,数学成绩:%d,英语成绩:%d,语文成绩:%d\n" , name, math, english, chinese); } if (feof(file)) { printf ("文件读取完毕" ); } else if (ferror(file)) { perror("发生了读取错误" ); return 1 ; } fclose(file); file = NULL ; } else { perror("文件打开失败" ); return 1 ; } return 0 ; }
移动指针 fseek
函数用于移动文件指针在文件流中的位置;stream
是指向FILE
结构的指针,它标识了文件流;offset
表示偏移量,它用于确定文件指针在文件流中的新位置;whence
表示相对位置的基准,可以取以下三个常量值
SEEK_SET
:从文件的起始位置开始偏移offset
个字节SEEK_CUR
:从当前文件位置开始偏移offset
个字节SEEK_END
:从文件末尾位置开始偏移offset
个字节 fseek
的返回值是一个整数,通常用于检查是否定位成功,如果成功,返回值为0
;否则返回非零值。
1 int fseek (FILE *stream, long offset, int whence) ;
如下代码将文件指针移动到倒数第一个字符之前,那么fgetc
将只能读取倒数第一个字符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 typedef char * String;int main () { String filePath = "E:\\temp\\test.txt" ; FILE* file = fopen(filePath, "r" ); if (file != NULL ) { fseek(file, -1 , SEEK_END); int character; char buffer[1024 ] = {0 }; for (int i = 0 ; (character = fgetc(file)) != EOF; i++) { buffer[i] = (char )character; } if (feof(file)) { printf ("character = %s" , buffer); } else if (ferror(file)) { perror("发生了读取错误" ); return 1 ; } fclose(file); file = NULL ; } else { perror("文件打开失败" ); return 1 ; } return 0 ; }
错误处理 在进行文件操作时,需要考虑错误处理。可以使用feof
函数检查文件是否已经到达末尾,以及使用ferror
函数检查文件操作是否发生了错误
1 2 3 4 5 if (feof(file)) { } else if (ferror(file)) { }