本文使用 Zhihu On VSCode 创作并发布
在笔记Day3最后的代码中,在使用fprintf和fwrite分别对文件进行写入操作时,发现了这样一个问题。
从键盘输入两个学生数据,先用fprintf()写入stu_list.txt文件中,再用fscanf()读出这两个学生的数据显示在屏幕上。然后再用 fwrite()写入 stu_list.dat 中,用 fread()读出这两个学生数据显示在屏幕上。
#include<stdio.h>
#include<stdlib.h>
struct stu{
char name[10];
int num;
};
int main(){
FILE *fp;
int i;
struct stu a[2],b[2];
if((fp=fopen("stu_info.txt","w+"))==NULL){ // 以读写方式打开文件"stu_info.txt"
printf("open error");
getchar();
exit(1);
}
//输入数据
printf("ninput datan");
for(i=0;i<2;i++){
scanf("%s%d",a[i].name,&a[i].num);
}
//输出数据到文件指针所指向文件
for(i=0;i<2;i++){
fprintf(fp,"%st%dn",a[i].name,a[i].num);
}
//关闭文件,保证缓冲区的信息写入到文件中
fclose(fp);
//再次以读写方式打开文件"stu_info.txt"
if((fp=fopen("stu_info.txt","r"))==NULL){
printf("open error");
getchar();
exit(1);
}
// 把文件内部位置指针移到文件首,用fscanf读出两个学生数据
rewind(fp);
for(i=0;i<2;i++){
fscanf(fp,"%s%d",b[i].name,&b[i].num);
}
printf("nfprintf && fscanf ");
printf("nnnametnumbern");
for(i=0;i<2;i++){
printf("%st%dn",b[i].name,b[i].num);
}
fclose(fp);
if((fp=fopen("stu_info.dat","w+"))==NULL){
printf("open error");
getchar();
exit(1);
}
// 用 fwrite()来写入文件
fwrite(a,sizeof(struct stu),2,fp);
fclose(fp);
//再次以只读形式打开文件
if((fp=fopen("stu_info.dat","r"))==NULL){
printf("open error");
getchar();
exit(1);
}
rewind(fp);
fread(b,sizeof(struct stu),2,fp);
printf("nfwrite && fread ");
printf("nnnametnumbern");
for(i=0;i<2;i++){
printf("%st%dn",b[i].name,b[i].num);
}
fclose(fp);
return 0;
}
运行结果如图所示
但是当我从硬盘中打开文件时,发现使用 fprintf 写入文件在记事本中的显示是正常的,而使用 fwrite 在文件中数字部分却变成了乱码而且并没有换行
那么,是什么原因造成了这种问题呢?
我在 C Primer Plus 中找到了这样一句话:
ANSI C 提供两种文件打开模式 :二进制和文本。以二进制打开文件时,可以逐字节读取文件;以文本模式打开文件时,会把文件内容从文本的系统表示法映射为 C 表示法。
众所周知,fprintf 写入文件时使用的是文本模式,fwrite 写入文件时使用的是二进制模式。
所以在存储一个数时(例如10001),fprintf 将其视为 5 个字符并保存在5个字节中(相当于将这个数拆分成 5 个单字符),每个单字符都能在 ASCii 表中找到对应的映射从而正确显示;
而 fwrite 则使用该数的二进制表示(相当于将这个数看成一个整体),并将其存储为一个4字节的整数,而这样的二进制数自然是无法被识别从而显示为乱码的。
而对于一个字符串,两者并没有差别,都是将该字符串储存为一个单字节的二进制码,所以两种函数输出的字符串在文件中都可以正确显示。
同时,二进制文件和文本文件格式对于系统的依赖性不同,在读写流时程序执行的转换支持也不同(二进制流不转换,而文本流需要转换换行符和其他功能字符)。因此在 fwrite 输出的文件中没有显示换行。