2. 文本文件的读写操作
当 fopen 函数打开文件时,第二个参数 mode(打开模式)中含有 t 标志或 没有 b 标志时则为以文本方式打开文件。当以文本文件打开文件时,建议使用文本文件读写相关的函数进行操作。
文本文件的写操作
文本文件写入操作常用的函数有 fputc、fputs、fprintf。
文本文件写入相关的函数
函数
说明
int fputc(int c, FILE *stream);将一个字符串
c 转为无符号unsigned char 后写入文件 stream。int fputs(const char *str, FILE *stream);一个字符串
str 写入文件 stream,不写入字符串的尾零 \0。int fprintf(FILE *stream, const char *format, ...);使用
printf 函数的方式将格式化后的数据写入文件 stream。示例:
// filename: text_write.c
#include <stdio.h>
int main(int argc, char * argv[]) {
FILE * pf = NULL; // 用于保存已经打开的文件
pf = fopen("myinfo.csv", "w");
if (NULL == pf) {
perror("打开文件 myinfo.csv");
return -1;
}
// 以下写入一行 "1,weimingze,35\r\n"。
fputc('1', pf); // 写入一个 "1"
fputc(',', pf); // 写入一个 逗号
fputs("weimingze,35\r\n", pf); // 写入 14 个字节
// 以下写入一行 "2,laowei,18\r\n"。
fprintf(pf, "%d,%s,%d\r\n", 2, "laowei", 18);
// 关闭文件
fclose(pf);
return 0;
}
编译和运行结果如下:
weimingze@mzstudio:~$ ls
text_write.c
weimingze@mzstudio:~$ gcc -o text_write text_write.c
weimingze@mzstudio:~$ ./text_write
weimingze@mzstudio:~$ ls
myinfo.csv text_write text_write.c
weimingze@mzstudio:~$ cat myinfo.csv
1,weimingze,35
2,laowei,18
说明:
可见上述程序生成的 myinfo.csv 文件的内容是
1,weimingze,35
2,laowei,18
Linux/Mac OS 终端中使用 cat myinfo.csv 命令是显示文件 myinfo.csv 文件的内容。此时的 mycsv 文件是标准的 csv 格式的文件,这个文件可以使用电子表格软件(如:wps)打开。打开后的效果如下:

文本文件的读操作
文本文件读取操作常用的函数有 fgetc、fgets、fscanf。
文本文件读取相关的函数
函数
说明
int fgetc(FILE *stream);从文件流(
stream)中读取下一个字符,成功则返回 unsigned char 转为 int 的值,失败则返回 EOF(值为-1)char *fgets(char *s, int size, FILE *stream);从文件流(
stream)中读取最多 size -1 个字符形成字符串放入 s 指向的内存缓冲区中,读取到文件结束(EOF)或换行符则结束读取。在缓冲区末尾添加尾零 '\0'。int fscanf(FILE *stream, const char *format, ...);从文件流
stream 中使用 scanf 函数的方式读取数据到相应的变量中。成功返回读取的数据的个数,失败返回 EOF。示例:
将上述 myinfo.csv 文件的内容读取出来,将其打印在终端中。
// filename: text_read.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char * argv[]) {
FILE * pf = NULL; // 用于保存已经打开的文件
int number; // 用于保存编号
char name[100]; // 用于保存性命
int age; // 用于保存年龄。
pf = fopen("myinfo.csv", "r");
if (NULL == pf) {
perror("打开文件 myinfo.csv");
return -1;
}
// 循环 读取,直至失败时才退出循环
while (1) {
// 读取一行数据并打印,数据的格式为: "1,weimingze,35\r\n"。
int temp; // 用来保存临时的数据
char buf[120]; // 用于保存一段文件的内容。
char * find; // 用于记录查找字符时找到的位置。
// 使用scanf读取前面的数字,如果返回 EOF 说明没有读取到数据
if (EOF == fscanf(pf, "%d", &number)) {
break; // 没有数据了
}
temp = fgetc(pf); // 读取一个逗号分隔符
if (temp != ',') {
printf("文件格式出错!\n");
break;
}
// 读取一行中剩余的部分。格式为: "weimingze,35\r\n"
if (NULL == fgets(buf, sizeof(buf), pf)) {
printf("文件格式有错!");
break;
}
// 查找逗号的位置,用于解析出姓名。
find = strstr(buf, ",");
if (NULL == find) {
printf("姓名后没有找到逗号!\n");
break;
}
// 先将 find 指向的逗号该成 `\0`, 作为姓名字符串的尾零。
*find = '\0';
// 将buf开始,到 find 之间的字符复制到name
strcpy(name, buf);
find++; // find 指向 下一个字符(年龄的开始)。
age = atoi(find); // 将字符串转为整数,末尾的"\r\n" 会被忽略。
// 打印获取到的姓名等信息
printf("编号: %d, 姓名: %s, 年龄: %d\n", number, name, age);
}
// 关闭文件
fclose(pf);
return 0;
}
编译和运行结果如下:
weimingze@mzstudio:~$ gcc -o text_read text_read.c
weimingze@mzstudio:~$ ./text_read
编号: 1, 姓名: weimingze, 年龄: 35
编号: 2, 姓名: laowei, 年龄: 18
上述程序中可以看出。当我们从文本文件中读取文件的信息时,需要手动解析文件的格式来获取每一行,每一列的数据。
练习
写两个程序
- 第一个程序连续输入多个学生的姓名、年龄、成绩,当输入姓名给空字符串时结束输入。将输入的内容保存到文件
student.txt中。 - 第二个程序从文件
student.txt中获取之前保存的所有学生的 姓名、年龄、成绩 等信息。然后打印到控制台终端上。
要求:使用文本文件的读写方式。自己定义文件 student.txt 的格式。