如果这篇博客帮助到你,可以请我喝一杯咖啡~
CC BY 4.0 (除特别声明或转载文章外)
在学习 C 语言时,我们知道:
一 文本文件与二进制文件
<stdio.h>
支持两种文件类型:文本文件和二进制文件
文本文件(text file)中,字节表示字符。(C程序的源代码就储存在文本文件中)
二进制文件(binary file)中,字节不一定表示字符;字节组还可以表示其它类型的数据,比如整数与浮点数(可执行C程序存贮在二进制文本中)
文本文件中二进制文件没有的特性:
1.文本文件分为若干行
文本文件的每一行通常以一两个特殊字符结尾。特殊字符与操作系统有关:
Windows中,行末标记是回车符(’\x0d’)+ 换行符(‘\x0a’)
Unix 与新的MacOS中,行末是一个单独的换行符
2.文本文件可以包含一个特殊的“文件末尾”标记
一些操作系统允许在文本文件的末尾使用一个特殊字节作为标记。在Windows中,标记为 ‘\x1a’ (Ctrl + Z)。
Ctrl + Z 不是必须的,但如果存在, 它就标志着文件的结尾,其后所有的字节都被忽略。
大多数其他操作系统(包括UNIX)没有专门的文件末尾符
二进制文件不分行,也没有行末标记和文件末尾标记 ,所有字节都是平等对待的
例1:向文件写入数据时,我们需要考虑按文本格式存储还是按二进制格式进行存储。为了搞清其中的差别,考虑在文件中存储数32767的情况。
从上例可以看出:
二进制形式存储数据可以节省相当大的空间
总结:
在屏幕上显示文件内容的程序可能要把文件视为文本文件。但是,文件复制程序就不能认为要复制的文件为文本文件(考虑到文本文件可能含有文件末尾字符,这样就不能复制完全)。
在无法确定文件是文本文件还是二进制文件时,安全的做法是把文件假定为二进制文件。
二 C 与 C++ 对文本文件和二进制文件的操作
1. NotePad++ 的 HexEditor 插件
使用 NotePad++ 的 HexEditor 插件可以在文件中看到数据编码前的格式。
2. C
文本文件
void test6pp()
{
FILE* fp = fopen("text.c.txt", "w+");
struct Student s = { "Shepard Wang", 20, "man" };
fprintf(fp, "%s%d%s", s.name, s.age, s.gender);
}
我们打开text.c.txt
文件,看到:
写入文件成功,我们再来试试读取:
void test6pp()
{
FILE* fp = fopen("text.c.txt", "w+");
struct Student s = { "Shepard Wang", 20, "man" };
fprintf(fp, "%s%d%s", s.name, s.age, s.gender);
fclose(fp);
// 读取
FILE* fp2 = fopen("text.c.txt", "r");
struct Student s2;
// 读取出现错误
// s2.name 是 Shepard,遇到空格结束读取
fscanf(fp2, "%s%d%s", s2.name, &s2.age, s2.gender);
fclose(fp2);
}
取消姓名中的空格:
struct Student s = { "ShepardWang", 20, "man" };
再试试?发现 s2.name 把所有数据都读完了,因此,在写文件时,最好给不同的数据项之间加上空格或换行:
fprintf(fp, "%s %d %s", s.name, s.age, s.gender);
这下就可以正确的读取了。
二进制文件
void test6ppp()
{
FILE* fp = fopen("binary.c.txt", "w+");
struct Student s = { "ShepardWang", 20, "man" };
fwrite(&s, sizeof(s), 1, fp);
fclose(fp);
}
注意一下文本文件和二进制文件中 20 的存储格式:
就像上面 一 中说的那样。
读取二进制文件:
void test6ppp()
{
FILE* fp = fopen("binary.c.txt", "w+");
struct Student s = { "ShepardWang", 20, "man" };
fwrite(&s, sizeof(s), 1, fp);
fclose(fp);
FILE* fp2 = fopen("binary.c.txt", "r");
struct Student s2;
fread(&s2, sizeof(s2), 1, fp2);
fclose(fp2);
}
我们可以二进制文件可以整块的读取,效率高(而且不用操心空格换行
3. C++
文本文件
void test6p()
{
// 文本格式写文件
ofstream text("text.cpp.txt");
struct Student s = { "Shepard_Wang", 20, "man" };
text << s.name << " " << s.age << " " << s.gender << endl;
text.close();
ifstream text2("text.cpp.txt");
struct Student s2;
text2 >> s2.name >> s2.age >> s2.gender;
text2.close();
}
二进制文件
void test6cpppp()
{
ofstream text("binary.cpp.txt");
struct Student s = { "Shepard_Wang", 20, "man" };
text.write((char*)&s, sizeof(s));
text.close();
ifstream text2("binary.cpp.txt");
struct Student s2;
text2.read((char*)&s2, sizeof(s2));
text2.close();
}
三 思考
1. 能否用 read 读取文本文件?或者用 » 读取二进制文件?
对应的 C 语言的问题就是 “能否用 fscanf 读取二进制文件?能否用 fread 读取文本文件?”
文本文件和二进制文件的存储方式不同:
文本文件是按照字符存储,数据项用空字符隔开;而二进制文件是按照字节存储。
如果混用,肯定会造成混乱。