一、先问同学们一个问题
平时我们看到一个.txt文件,打开以后是:
Hello看到一张图片,打开以后是一张照片。
那么问题来了:
计算机眼里的文件,到底是什么?
答案其实非常简单:
文件本质上就是一串二进制数据,也就是很多个 0 和 1。
例如:
01001000 01100101 01101100 01101100 01101111这串二进制数据,计算机可以把它解释成:
Hello所以可以告诉大家:
文件不是“文字”“图片”或者“视频”本身。
文件本质上只是一串 0 和 1。
我们看到的文字、图片、音乐,只是计算机按照不同规则解释这些 0 和 1 后得到的结果。
二、普通文本编辑器为什么看不到二进制?
例如我们创建一个:
hello.txt里面写:
ABC用记事本打开:
ABC孩子可能会问:
“不是说文件里面是 0 和 1 吗?为什么我看到的是 ABC?”
这是因为:
记事本帮我们把二进制翻译成我们人类能看懂的文字了。
就像:
计算机语言: 01000001 01000010 01000011 ↓ 翻译 人类语言: A B C所以普通文本编辑器实际上是一个:
“翻译员”
三、“十六进制编辑器”
如果想直接观察文件里面的数据,可以使用:
Hex Editor(十六进制编辑器)
它也叫:
Hex Editor / 十六进制编辑器 / 二进制编辑器
这里特别要给大家解释一个容易产生的误解:
“十六进制编辑器”是不是只能看十六进制?
不是。
它看到的其实就是:
文件中的原始字节(byte)
只不过为了方便程序员阅读,它通常把一个字节显示成两个十六进制数字。
例如:
01000001二进制:
01000001转换成十六进制:
41所以我们经常会看到:
41 42 43实际上就是:
01000001 01000010 01000011也就是:
A B C四、推荐同学们使用什么工具?
对于初学者,我比较推荐:
① HxD
这是 Windows 上非常经典的十六进制编辑器。
HxD 官方网站
它特别适合用来学习:
二进制文件
十六进制
字节
ASCII
文件头
文件结构
而且界面非常直观。
五、打开一个文件看看
我们可以先创建一个非常简单的文件:
hello.txt里面输入:
ABC保存。
然后用 HxD 打开。
孩子可能会看到类似:
41 42 43旁边还可能看到:
ABC这时候就非常适合停下来问孩子:
为什么左边是 41 42 43,右边却是 ABC?
六、带同学们一起破解 41 42 43
我们来看看:
41 42 43这是十六进制。
一个十六进制数:
41实际上代表一个字节:
01000001而 ASCII 中:
01000001 = A 01000010 = B 01000011 = C所以:
41 42 43就是:
A B C可以画成这样:
文件 │ ├── 41 ───→ 01000001 ───→ A │ ├── 42 ───→ 01000010 ───→ B │ └── 43 ───→ 01000011 ───→ C这时候大家就真正理解了:
所谓“文件里的文字”,其实就是一串数字。
七、为什么我们不直接显示 0 和 1?
这是一个非常好的问题。
假设文件里面有:
8个字节用二进制显示:
01001000 01100101 01101100 01101100 01101111 ...一个字节要写:
8个二进制数字如果文件很大,就会非常非常长。
例如:
1 MB大约有:
1,048,576 个字节如果全部写成二进制:
1,048,576 × 8就是:
8,388,608个 0 和 1!
我们人类看起来会非常痛苦。
所以计算机专业人员通常使用:
十六进制
一个字节:
01001000只需要写成:
48是不是短很多?
所以:
二进制最接近计算机。
十六进制最方便人类观察二进制。
这是非常重要的一个知识点。
八、认识 Hex Editor 的三个区域
打开 HxD 后,通常可以看到类似这样的结构:
地址 十六进制数据 ASCII 00000000 41 42 43 44 45 46 47 48 ABCDEFGH 00000008 49 4A 4B 4C 4D 4E 4F 50 IJKLMNOP可以把它想象成三个窗口:
┌──────────┬───────────────────────┬─────────────┐ │ 地址 │ 二进制数据 │ 人类看到的 │ ├──────────┼───────────────────────┼─────────────┤ │ 00000000 │ 41 42 43 44 45 ... │ ABCDE... │ │ 00000010 │ 10 FF 3A 82 ... │ ... │ └──────────┴───────────────────────┴─────────────┘第一部分:地址
例如:
00000000 00000001 00000002 ...表示:
这个字节在文件的什么位置。
第二部分:十六进制
例如:
41 42 43这才是文件真正存储的数据。
第三部分:ASCII
例如:
ABC这是工具帮我们翻译后的结果。
九、最有意思的实验:自己修改文件
这个实验非常推荐。
我们刚才有:
ABC十六进制:
41 42 43那么我们把:
41改成:
44保存。
再用记事本打开。
你猜会发生什么?
答案:
DBC为什么?
因为:
41 → A 42 → B 43 → C 44 → D所以:
41 42 43变成:
44 42 43也就变成:
D B C这时候同学们会突然发现:
原来我真的可以直接修改文件里的“底层数据”!
这比单纯讲概念有意思得多。
十、再做一个“图片实验”
这次可以找一张小图片,例如:
test.png用十六进制编辑器打开。
你会看到大量类似:
89 50 4E 47 ...可能还有:
49 48 44 52等等。
孩子可能会问:
“老师,这些乱七八糟的数字是什么?”
这时候告诉他:
图片也是数据。
图片并不是计算机里面的一幅“画”。
它实际上也是:
一大堆字节只不过图片软件知道:
这些字节按照 PNG 规则解释于是:
字节 ↓ PNG解析规则 ↓ 图片而文本软件则是:
字节 ↓ 字符编码规则 ↓ 文字所以特别重要的一句话是:
同样是一堆 0 和 1,不同的软件按照不同规则解释,就可以变成文字、图片、音乐、视频……
十一、顺便认识一个非常重要的概念:文件头
打开很多二进制文件时,你会发现:
文件开头的一些字节非常特殊。
例如 PNG 图片开头有固定的文件标识。
这就像什么?
同学们可以理解成:
文件的“身份证”。
例如:
文件 │ ├── 文件头 │ ↓ │ “我是 PNG!” │ ├── 图片数据 │ ├── 图片数据 │ └── ...很多文件格式都有自己的“身份证”。
例如:
PNG JPG PDF ZIP EXE MP3它们内部的字节排列规则都不一样。
这就给后面学习:
文件格式
二进制文件
文件读写
fstreamifstreamofstreamread()write()
打下了非常好的基础。
十二、把这个知识和 C++ 联系起来
这一步对于正在学 C++ 的小学生尤其重要。
我们之前可能写过:
ofstream fout("data.txt"); fout << "ABC"; fout.close();这里:
fout << "ABC";最终并不是把“ABC”三个神奇的字符直接塞进硬盘。
而是经过字符编码,最终变成字节。
例如 ASCII 情况下:
A → 41 B → 42 C → 43于是文件里面就有:
41 42 43十三、再进一步:C++直接读“字节”
以后学习二进制文件时,我们可以使用:
#include <iostream> #include <fstream> using namespace std; int main() { ifstream fin("hello.txt", ios::binary); char c; while (fin.get(c)) { cout << (int)(unsigned char)c << " "; } fin.close(); return 0; }如果文件里面是:
ABC那么可能输出:
65 66 67注意这里是十进制。
因为:
A = 65 B = 66 C = 67换成十六进制就是:
41 42 43于是我们终于把:
C++程序 ↓ 读取文件 ↓ 字节 ↓ 十进制 / 十六进制 ↓ 二进制整个过程串起来了。
十四、给同学们建立一张“地图”
文件 │ ↓ ┌─────────────┐ │ 一串字节 │ └─────────────┘ │ ┌──────┴──────┐ ↓ ↓ 十六进制 二进制 │ │ 41 42 43 01000001... │ ↓ 字符编码 │ ↓ ABC最重要的是理解:
41不是一个“字母 A”。
它首先是一个数字/字节的表示。
按照 ASCII 规则解释:
41 → A按照其他规则,它可能代表完全不同的东西。
十五、我们进行一个“文件侦探”实验
🕵️ 文件侦探任务
任务1
创建:
hello.txt输入:
ABC然后用 HxD 打开。
找到:
41 42 43任务2
把:
41修改成:
44看看文本发生什么变化。
任务3
找一个图片文件,用 HxD 打开。
观察:
文件开头是什么样的?
任务4
再找一个:
PDF ZIP MP3文件。
分别打开看看。
同学们来思考:
为什么它们开头的数据不一样?
十六、最后给同学们留三个“金句”
金句1
文件的本质,是硬盘里保存的一串字节。
金句2
二进制是计算机最熟悉的语言,十六进制是程序员观察二进制的好工具。
金句3
文字、图片、音乐、视频,本质上都是数据;区别只是“解释这些数据的规则”不同。
如果同学们把这三句话真正理解了,那么对C++文件操作、二进制文件、内存、指针、字符编码、文件格式的理解会一下子串起来。