Crash Course Computer Science【计算机科学速成课】(2)
感谢速成课!感谢 Carrie Anne!感谢中文翻译组!~
原视频
Crash Course Computer Science
https://github.com/1c7/crash-course-computer-science-chinese
第 11 集:编程语言发展史
计算机只能处理二进制,二进制是处理器的”母语”,称为machine language或machine code
在计算机早期阶段,必须用机器码写程序
- 先在纸上用英语写一个”高层次版”,这种对程序的高层次描述叫“伪代码”,在纸上写好后用“操作码表”转成机器码,喂入计算机运行。
在 1940~1950 年代,程序员开发出一种新语言,更可读、更高层次,每个操作码分配一个简单名字,叫”助记符“,”助记符”后面紧跟数据,形成完整指令。
- 比如存指令在内存地址
0:0010 1110,前 4 位是操作码,假设对某CPU0010代表LOAD_A指令,即把值从内存复制到寄存器A,后 4 位是内存地址,1110是十进制的 14,所以这 8 位表达的意思是 “读内存地址 14,放入寄存器 A”
- 比如存指令在内存地址

但是CPU不知道
LOAD_A 14是什么,于是有了汇编器,它可以读取用”汇编语言”写的程序,然后转成”机器码”。- 随着时间推移,汇编器有越来越多功能,让编程更容易,比如自动分析JUMP地址,汇编器不用固定跳转地址,而是让你插入可跳转的标签,当程序被传入汇编器,汇编器会自己搞定跳转地址,程序员可以专心编程,不用管底层细节。

- 随着时间推移,汇编器有越来越多功能,让编程更容易,比如自动分析JUMP地址,汇编器不用固定跳转地址,而是让你插入可跳转的标签,当程序被传入汇编器,汇编器会自己搞定跳转地址,程序员可以专心编程,不用管底层细节。
一般来说,一条汇编指令对应一条机器指令,所以汇编码和底层硬件的连接很紧密,汇编器仍然强迫程序员思考,用什么寄存器和内存地址。于是 Hopper 设计了一种高级语言,一行高级编程语言,可能会转成几十条二进制指令。为了做到这种复杂转换,Hopper 在 1952 年创造了第一个编译器,编译器专门把高级语言,转成低级语言,比如汇编或机器码(CPU 可以直接执行机器码)。
- FORTRAN,名字来自 “公式翻译”,这门语言数年后由 IBM 在 1957 年发布,主宰了早期计算机编程
FORTRAN 项目总监 John Backus 说过
“Much of my work has come from being lazy.I didn’t like writing programs,
and so … I started work on a programming system to make it easier to write programs.”
- FORTRAN,名字来自 “公式翻译”,这门语言数年后由 IBM 在 1957 年发布,主宰了早期计算机编程
当时 IBM 在卖计算机,因此最初 FORTRAN 代码只能跑在 IBM 计算机上。1950 年代大多数编程语言和编译器,只能运行在一种计算机上,如果升级电脑,可能要重写所有代码,因此工业界,学术界,政府的计算机专家,在 1959 年组建了一个联盟,数据系统语言委员会,Grace Hopper 担任顾问,开发一种通用编程语言,可以在不同机器上通用,最后诞生了一门高级,易于使用,”普通面向商业语言”,简称 COBOL。
- 为了兼容不同底层硬件,每个计算架构需要一个 COBOL 编译器,最重要的是,这些编译器都可以接收相同 COBOL 代码,不管是什么电脑,这叫”一次编写,到处运行”。
编程语言设计的黄金时代才刚刚开始,和硬件一起飞速发展
- 在 1960 年代,有 ALGOL, LISP 和 BASIC 等语言 70年代有:Pascal,C 和 Smalltalk
- 80年代有:**C++**,Objective-C 和 Perl
- 90年代有:Python,Ruby 和 Java 新千年 Swift, C#, Go 在崛起
第 12 集 编程原理
- 以游戏为切入点讲解条件语句,循环语句,函数的使用,体会函数的强大之处和现代编程的核心
it's not magic,it's the power of abstraction
- 比如浏览器这样的复杂程序,用一长串语句来写是不可能的,会有几百万行代码,没人能理解,所以现代软件由上千个函数组成,每个负责不同的事。
如今超过100行代码的函数很少见,如果多于 100 行,应该有东西可以拆出来做成一个函数,符合软件设计中“高内聚低耦合”的原则。 - 模块化编程,不仅可以让单个程序员独立制作 App,也让团队协作可以写更大型的程序,不同程序员写不同函数,只需要确保自己的代码工作正常。
- 现代编程语言 有很多预先写好的函数集合,叫 “库“,由专业人员编写,不仅效率高,而且经过了仔细检查,几乎做所有事情都有库,网络、图像、声音。
第 13 集 编程入门
- 如何想出高效的算法是早在计算机出现前就有的问题,记载最多的算法之一是“排序”。
- 输入大小和运行步骤数之间的关系称为算法的复杂度,计算机科学家们用“大O表示法”,来表示运行速度的量级。
- 比如 O(N)效率并不高,比如”归并排序”的算法复杂度是 O(n * log n),n 是每次合并需要比较的次数和数组大小成正比,log N 是合并步骤的次数。

- 比如 O(N)效率并不高,比如”归并排序”的算法复杂度是 O(n * log n),n 是每次合并需要比较的次数和数组大小成正比,log N 是合并步骤的次数。
- 图搜索算法也有很多,有不同优缺点,每次用谷歌地图时,类似Dijkstra 的算法就在服务器上运行,寻找最佳路线,现实世界中算法无处不在。
第 14 集 数据结构
- 数组(Array)也叫列表(list)或向量(Vector)(在其它编程语言里),数组的值一个个连续存在内存里。
- 可以把多个值存在数组变量里,为了拿出数组中某个值,我们要指定一个下标(index)。大多数编程语言里,数组下标都从 0 开始,用方括号 [ ] 代表访问数组。
- 下标可以理解为偏移量,
offset为 0 ,说明为数组中第一个数。

- 字符串在内存里以 0 结尾,不是”字符0”,是”二进制值0”,这叫字符”null“,表示字符串结尾。如果调用 print 在屏幕上输出字符串,会从开始位置,逐个显示到屏幕,直到遇到
null值停止。 - 多个变量打包在一起叫结构体 (Struct),结构体可以创建复杂的数据结构。
- 一个结构体存一个变量,一个指针(pointer)叫一个节点(node),”指针“是一种特殊变量(注意区分指针和指针变量),指向一个内存地址,用节点可以做链表(linked list)。
- 链表是一种灵活数据结构,能存很多个节点 (node),灵活性是通过每个节点指向下一个节点实现的。

- 第一个节点,值是 7,指向地址
1008,代表下一个节点,位于内存地址1008,下一个节点值是 112,指向地址1002是一个值为 14 的节点。这个节点指回地址1000,也就是第一个节点。这叫循环链表,但链表也可以是非循环的,最后一个指针是 0,”null“,代表链表尽头。

- 第一个节点,值是 7,指向地址
- 数组大小需要预先定好,链表大小可以动态增减。
- 可以创建一个新节点,通过改变指针值,把新节点插入链表,链表也很容易重新排序,两端缩减,分割,倒序等。
- 很多复杂数据结构都用链表,比如队列(queue)和 栈(stack)
- 队列先进先出(FIFO),栈后进先出(LIFO) 术语叫”入栈”(push) “出栈”(pop)。
- 如果节点改一下,改成 2 个指针就能做树(tree)。
- 很多算法用了 “树” 这种数据结构,同样,程序员很少看指针的具体值,而是把”树”抽象成这样:最高的节点叫”根节点“(root),”根节点”下的所有节点都叫”子节点“(children),任何子节点的直属上层节点,叫”母节点“(parent node),没有任何子节点的节点,也就是“树”结束的地方叫“叶节点”。
第 15 集 阿兰·图灵
- 计算机科学之父阿兰·马蒂森·图灵于 1921 年出生在伦敦,从小就表现出惊人数学和科学能力。他对计算机科学的建树始于 1935 年,当时他是剑桥国王学院的硕士生,他开始解决德国数学家大卫·希尔伯特提出的问题,叫 Entscheidungsproblem (德语)即”可判定性问题“:是否存在一种算法,输入正式逻辑语句,输出准确的”是”或”否”答案?
- 图灵提出了一种假想的计算机,现在叫“图灵机”。图灵机是一台理论计算设备,有一个状态变量保存当前状态,一组规则描述机器着什么,可能是在纸带写入一个符号,或把读写头移动一格,或执行这些动作的组合。

- 比如读一个以零结尾的字符串,并计算 1 的出现次数,出现偶数次在纸带上写一个 1 ,奇数次写一个 0 。要使用图灵机来实现这一动作首先要定义规则,当前符号为 1 ,状态更新为奇数或偶数,读写头向右移动,如果当前符号是 0 ,状态为偶数那么在纸带上写一个 1,状态改为停机。

- 比如读一个以零结尾的字符串,并计算 1 的出现次数,出现偶数次在纸带上写一个 1 ,奇数次写一个 0 。要使用图灵机来实现这一动作首先要定义规则,当前符号为 1 ,状态更新为奇数或偶数,读写头向右移动,如果当前符号是 0 ,状态为偶数那么在纸带上写一个 1,状态改为停机。
- 图灵证明了这个假想机器如果有足够的时间和内存,可以执行任何计算,他是一台通用计算机,一个可以创造任何东西的强大计算模型!但“停机问题”证明了不是所有问题都能用计算解决。
- 丘奇和图灵证明了计算是有极限的,起步了可计算性理论,现在叫”丘奇-图灵论题”。当时是1936年,图灵只有24岁。从1936年到1938年在丘奇指导下,他在普林斯顿拿到博士学位。毕业后回到剑桥,1939年后不久,英国卷入第二次世界大战。整个战争期间,图灵和同事在布莱切利园努力破解加密,位于”布莱切利园”的一个密码破译组织,他的工作内容之一是破解德国的通信加密,特别是”恩尼格玛机“加密的信息。
- 战后,图灵回到学术界为许多早期计算机工作做出贡献,比如曼彻斯特 1 号,一个早期有影响力的存储程序计算机,但他最有名的战后贡献是”人工智能“。1950 年,图灵设想了未来的计算机,拥有和人类一样的智力,或至少难以区分,图灵提出如果计算机能欺骗人类相信它是人类,才算是智能。你可以问他问题,如果你区分不出来哪个是人类,哪个是计算机,那么计算机就通过了图灵测试。
- 图灵那个时代,同性恋在英国和大部分国家都是违法的,1952 年调查他家的入室盗窃案时,向当局暴露了他的性取向,被起诉 “行为严重不检点”。图灵被定罪,有2个选择:1.入狱2.接受激素来压制性欲,他选了后者,部分原因是为了继续学术工作,但药物改变了他的情绪和性格,图灵于1954年服毒自尽,年仅41岁。
第 16 集 软件工程
- 微软的 Office 大约有 4000 万代码,为了写大型程序,程序员用各种工具和方法,所有形成了”软件工程”学科。把大项目分解成小函数,可以让多人同时工作,如果只是这样,微软 Office 会有几十万个函数还是太多了,解决办法是:把函数打包成层级,把相关代码都放在一起,打包成对象(objects)。
- 例如,汽车软件中可能有几个和定速巡航有关的函数,比如 设定速度,逐渐加速减速,停止定速巡航因为这些函数都相关,可以包装成一个”定速巡航对象”。可能还有 “火花塞点火” “燃油泵” 和 “散热器”,我们可以做一个”引擎对象” 来包括所有”子”对象。同时也可能有自己的函数和变量。
- 总的来说,对象可以包其它对象,函数和变量。把函数打包成对象的思想叫 “面向对象编程“
- 其他团队阅读代码时需要文档帮助理解代码都做什么,以及定义好的 “程序编程接口” -简称API,API 帮助不同程序员合作不用知道具体细节,只要知道怎么使用就行了。”面向对象”的编程语言可以指定函数是 public 或 private,来设置权限,”面向对象”的编程语言可以指定函数是 public 或 private,来设置权限,如果函数标记成 private意味着 只有同一个对象内的其他函数能调用它。
- “面向对象”的核心是隐藏复杂度,选择性的公布功能。因为做大型项目很有效,所以广受欢迎,计算机上几乎所有软件,游戏机里几乎所有游戏
都是 “面向对象” 编程语言写的,比如 C++, C#, Objective-C 等。 - 集成开发环境,简称 IDE,IDE 帮助开发者整理和看代码,很多 IDE 还可以直接编译和运行代码,定位到出错代码,还会提供信息帮你解决问题这叫调试(debug)。
- 大多数程序员会花 70%~80% 时间调试,而不是在写代码,好工具能极大帮助程序员防止和解决错误。程序员工作的另一个重要部分是给代码写文档,文档一般放在一个叫 README 的文件里告诉其他程序员,看代码前先看这个文件,文档也可以直接写成”注释”,放在源代码里。
- 源代码管理也叫”版本控制“帮助团队协作,把代码放到一个中心服务器上叫”代码仓库”,这样多名程序员可以同时写代码,建立庞大的系统。源代码管理可以跟踪所有变化,如果发现 bug,全部或部分代码,可以”回滚”到之前的稳定版,”源代码管理” 也记录了谁改了什么代码。
- 测试一般由个人或小团队完成,测试可以统称 “质量保证测试”,简称 QA。严格测试软件的方方面面,模拟各种可能情况,看软件会不会出错,基本上就是找 bug,解决大大小小的错误需要很多工作但对确保软件质量至关重要,让软件在各种情况下按预期运行。
- “beta 版” 软件,意思是软件接近完成但不是100%完全测试过。公司有时会向公众发布 beta 版,以帮助发现问题,用户就像免费的 QA 团队。
- alpha 版本般很粗糙,错误很多,经常只在公司内部测试。
第 17 集 集成电路 & 摩尔定律
- 大约 1940年代~1960年代中期这段时间里计算机都由独立部件组成叫”分立元件”,然后不同组件再用线连在一起。1950 年代中期,晶体管开始商业化(市场上买得到),但晶体管依然是分立元件。
- 解决方法就是把多个组件包在一起,变成一个新的独立组件,这就是集成电路(IC),在1959年 Robert Noyce 的仙童半导体让集成电路变为现实,仙童半导体公司用硅,硅的蕴藏量丰富,占地壳四分之一,也更稳定可靠,Noyce 被公认为现代集成电路之父。开创了电子时代,创造了硅谷(仙童公司所在地)。
- 为了创造更大更复杂的电路,于是有了印刷电路板,简称 PCB,PCB 可以大规模生产,无需焊接或用一大堆线,它通过蚀刻金属线的方式,把零件连接到一起。把 PCB 和 IC 结合使用可以大幅减少独立组件和电线,但做到相同的功能。
- 为了实现更复杂的设计,需要全新的制作工艺”光刻“。光把复杂图案印到材料上,比如半导体。晶圆做基础把复杂金属电路放上面,集成所有东西。
- 硅片顶部加一层薄薄的氧化层, 作为保护层然后加一层特殊化学品, 叫 “光刻胶”,光刻胶被光照射后会变得可溶可以用一种特殊化学药剂洗掉,把光掩膜盖到晶圆上,用强光照射挡住光的地方,光刻胶不会变化,光照到的地方,光刻胶会发生化学变化洗掉它之后,暴露出氧化层用另一种化学物质洗掉”氧化层”露出的部分, 蚀刻到硅层现在硅又露出来了。我们修改硅露出来的区域让它导电性更好,”掺杂”通常用高温气体来做,比如磷,渗透进暴露出的硅,改变电学性质最后一步,在氧化层上做通道放一层薄薄的金属,比如铝或铜,连接不同晶体管。
- 1965年,戈登·摩尔看到了趋势:每两年左右,得益于材料和制造技术的发展同样大小的空间,能塞进两倍数量的晶体管,叫摩尔定律。
- CPU 不是唯一受益的元件,大多数电子器件都在指数式发展:内存,显卡,固态硬盘,摄像头感光元件,等等。
- 专家们几十年来一直在预言摩尔定律的终结进一步做小,会面临 2 个大问题1. 用光掩膜把图案弄到晶圆上,因为光的波长,精度已达极限所以科学家在研制波长更短的光源,投射更小的形状2. 当晶体管非常小,电极之间可能只距离几个原子电子会跳过间隙,这叫:量子隧道贯穿。如果晶体管漏电,就不是好开关。
第 18 集 操作系统
我们需要一种方式让计算机自动运作,而不是让操作员去放程序,于是”操作系统“诞生了。
操作系统,简称 OS,其实也是程序,但它有操作硬件的特殊权限,可以运行和管理其它程序。操作系统一般是开机第一个启动的程序,其他所有程序都由操作系统启动。操作系统开始于 1950 年代那时计算机开始变得更强大更流行。
第一个操作系统加强了程序加载方式,之前只能一次给一个程序,现在可以一次多个,当计算机运行完一个程序,会自动运行下一个程序,这就叫“批处理”。
为了兼容不同型号外部设备,操作系统充当软件和硬件之间的媒介。更具体地说,操作系统提供 API 来抽象硬件,叫”设备驱动程序“,程序员可以用标准化机制和输入输出硬件(I/O)交互。
在单个 CPU 上通过调度来同时运行几个程序,如 print 函数运行需要一点时间,大概上千个时钟周期,但因为打印机比 CPU 慢,与其等着它完成操作,os会把程序休眠,运行另一个程序,把程序标记成可继续运行,之后在某时刻会安排给 CPU 运行,并继续 print 语句之后的下一行代码。使多个程序可同时进行,这叫做“多任务处理”。
同时运行多个程序会有一个问题,每个程序都会占一些内存,当切换到另一个程序时,我们不能丢失数据。解决方案是给每个程序安排一个专属内存块,举个例子,假设计算机一共有 10000 个内存位置,程序 A 分配到内存地址 0 到 999,而程序 B 分配到内存地址 1000 到 1999,

以此类推如果一个程序请求更多内存,操作系统会决定是否同意,如果同意,分配哪些内存块。这种灵活性会带来一个后果,可能分配到不连续的内存块,这对程序员来说就难以追踪了,为了隐藏这种复杂性,os会把内存地址虚拟化,叫“虚拟内存”,程序可以假定内存总是从地址 0 开始,而实际物理位置被隐藏和抽象了。os 会自动处理虚拟内存和物理内存之间的映射,这种机制使程序的内存大小可以灵活增减,叫“动态内存分配”。

这样对程序来说,内存就变成连续的了,如果一个程序出错,开始写乱七八糟的数据,它只能捣乱自己的内存,不会影响到其它程序,这叫 “内存保护“。这对防止恶意软件(如病毒)也很有用,例如,我们不希望其他程序有能力,读或改邮件程序的内存。如果有这种权限,恶意软件可能以你的名义发邮件,甚至窃取个人信息。
1970年代,计算机不仅能同时运行多个程序,还能让多用户同时访问,为了确保其中一个人不会占满计算机资源,开发了分时操作系统,意思是每个用户只能用一部分的处理器和内存,因为计算够快所以就算只分配到 1/50 的资源也足以完成许多任务。
早期分时操作系统中,最有影响力的是 Multics(多任务信息与计算系统),于 1969 年发布,Multics 是第一个从设计时就考虑到安全的操作系统,开发人员不希望恶意用户访问不该访问的数据。
Multics 的研究人员之一 Dennis Ritchie 曾说过”阻碍 Multics 获得商业成功的一个明显问题是从某种方面来说,它被过度设计了,功能太多了”。所以 Dennis 和另一个 Multics 研究员 Ken Thompson 联手打造新的操作系统,叫 Unix。
他们将 os 主要分为两部分,首先是核心功能,如内存管理,多任务和输入/输出处理,这叫“内核”(kernel)。第二部分是一堆有用的工具,但不是内核的一部分。紧凑的内核意味着功能没那么全面,原则即追求简单,也是后来的Linux系统一脉相承的原则。如果有错误发生就让内核“恐慌”(panic),调用他时机器会崩溃,这就是”内核恐慌“(kernel panic)。
这种简单性意味着 Unix 可以在更便宜更多的硬件上运行,使 Unix 在 Dennis 和 Ken 工作的贝尔实验室大受欢迎,越来越多开发人员用 Unix 写程序和运行程序,成为1970~80年代最流行的操作系统之一。
微软 1985 年发布的早期 Windows 虽然在 90 年代很流行,但却缺乏”内存保护”,当程序行为不当时,就会”蓝屏”。代表程序崩溃的非常严重,把系统也带崩溃了,幸好新版Windows有更好的保护,不会经常崩溃。
第 19 集 内存 & 储存介质
存储器(Storage)和内存(Memory)有点不同,任何写入”存储器“的数据,比如你的硬盘数据会一直存着,直到被覆盖或删除,断电也不会丢失。
最早的存储介质是打孔纸卡以及纸卡的亲戚打孔纸带,他们便宜耐用但是不好存临时值,读取慢且只能写入一次。J. Presper Eckert 在 1944 年建造 ENIAC 时发明了一种方法,叫”延迟线存储器“(Delay Line Memory)。
原理:拿一个管子装满液体,如水银管子一端放扬声器,另一端放麦克风扬声器发出脉冲时 会产生压力波压力波需要时间 传播到另一端的麦克风麦克风将压力波 转换回电信号用压力波的传播延迟 来存储数据假设有压力波代表 1,没有代表 0扬声器可以输出 1010 0111压力波沿管子传播,过了一会儿,撞上麦克风,将信号转换回 1 和 0如果加一个电路,连接麦克风和扬声器再加一个放大器(Amplifier)来弥补信号衰弱就能做一个存储数据的循环信号沿电线传播几乎是瞬时的,所以任何时间点只显示 1 bit 数据但管子中可以存储多个位(bit)

“延迟线存储器“的一大缺点是每一个时刻只能读一位 (bit),数据如果想访问一个特定的 bit,比如第 112 位(bit),你得等待它从循环中出现所以又叫 “顺序存储器”或”循环存储器”。而我们想要的是 “随机存取存储器”可以随时访问任何位置,增加内存密度也是一个挑战,把压力波变得更紧密,意味着更容易混在一起。虽然出现了其他类型的 “延迟线存储器”如 “磁致伸缩延迟存储器“,然而延迟线存储器在 1950 年代中期就基本过时了。
“磁芯存储器“,用了像甜甜圈的小型磁圈如果给磁芯绕上电线,并施加电流,可以将磁化在一个方向如果关掉电流,磁芯保持磁化如果沿相反方向施加电流磁化的方向(极性)会翻转这样就可以存 1 和 0 !如果只存 1 位不够有用,所以把小甜甜圈排列成网格有电线负责选行和列,也有电线贯穿每个磁芯, 用于读写一位(bit)更重要的是,不像”延迟线存储器”磁芯存储器能随时访问任何一位(bit)”。磁芯存储器” 从 1950 年代中期开始成为主流,流行了 20 多年而且一般还是手工编织的!

到 1951 年,Eckert 和 Mauchly 创立了自己的公司设计了一台叫 UNIVAC 的新电脑,最早进行商业销售的电脑之一,它推出了一种新存储:磁带。磁带可以在”磁带驱动器”内前后移动,里面有一个”写头”绕了电线,电流通过产生磁场导致磁带的一小部分被磁化,电流方向决定了极性,代表 1 和 0。还有一个”读头”,可以非破坏性地检测极性。虽然磁带驱动器很贵,但磁带又便宜又小,因此磁带至今仍用于存档。磁带的主要缺点是访问速度并且磁带是连续的,必须倒带或快进到达特定位置1950,60年代,有个类似技术是 “磁鼓存储器“,有金属圆筒,盖满了磁性材料以记录数据。滚筒会持续旋转,周围有数十个读写头等滚筒转到正确的位置,读写头会读或写 1 位(bit),数据为了尽可能缩短延迟,鼓轮每分钟上千转!
硬盘和磁鼓很相似原理是一样的,磁盘表面有磁性写入头和读取头,可以处理上面的 1 和 0。硬盘的好处是薄,可以叠在一起提供更多表面积来存数据。要访问某个特定 bit,一个读/写磁头会向上或向下移动,找到正确的磁盘然后磁头会滑进去就像磁鼓存储器一样,磁盘也会高速旋转所以读写头要等到正确的部分转过来访问任意数据,平均只要六分之一秒左右也叫寻道时间。
成本与速度间的平衡
一小部分高速+昂贵的内存,一部分稍慢+相对便宜些的内存,还有更慢+更便宜的内存,这种混合在成本和速度间取得平衡。

如今的硬盘可以轻易容纳 1TB 的数据,现代硬盘的平均寻道时间低于 1/100 秒,简单地提一下硬盘的亲戚,软盘。软盘是为了便携,在 1970~1990 非常流行。光学存储器于 1972 年出现,12 英寸的”激光盘”光盘(简称 CD)以及 90 年代流行的 DVD,功能和硬盘软盘一样,都是存数据。但用的不是磁性,光盘表面有很多小坑,造成光的不同反射,光学传感器会捕获到,并解码为 1 和 0。
如今,存储技术在朝固态前进,没有机械活动部件比如这个硬盘,以及 U 盘里面是集成电路(NAND闪存)。第一个 RAM 集成电路出现于 1972 年,成本每比特 1 美分使”磁芯存储器”迅速过时。如今成本下降了更多,机械硬盘被固态硬盘逐渐替代,简称SSD。由于 SSD 没有移动部件,磁头不用等磁盘转,所以 SSD 访问时间低于 1/1000 秒但还是比 RAM 慢很多倍所以现代计算机仍然用存储层次结构。
第 20 集 文件系统
- 随意排列文件数据完全没问题,但按格式排会更好这叫 “文件格式”。你可以发明自己的文件格式(!!!),程序员偶尔会这样做。但最好用现成标准,比如 JPEG 和 MP3。
- 最简单的是文本文件,也叫 TXT 文件,里面包含的是文字,就像所有其它文件,文本文件只是一长串二进制数。解码数据的关键是 ASCII 编码,第一个值 72 在 ASCII 中是大写字母 H,以此类推解码其他数字。
- 波形(Wave)文件,也叫 WAV 它存音频数据,在正确读取数据前,需要知道一些信息,比如码率(bit rate),以及是单声道还是立体声,关于数据的数据,叫”元数据“(meta data)。元数据存在文件开头,在实际数据前面,因此也叫 文件头(Header)。WAV 文件的前 44 个字节长这样

其他部分的内容,会根据数据变化。音频数据紧跟在元数据后面,是一长串数字,数字代表每秒捕获多次的声音幅度。 - 计算机上,图片由很多个叫”像素”的方块组成,每个像素由三种颜色组成:红,绿,蓝,用红绿蓝值或 RGB 值表示。就像 WAV 文件一样,BMP 文件开头也是元数据,有图片宽度,图片高度,颜色深度。
- 为了存多个文件需要一个特殊文件,记录其他文件的位置,这里泛称 “目录文件“,这个文件经常存在最开头,方便找到。目录文件里,存所有其他文件的名字,格式是文件名 + 一个句号 + 扩展名,比如 BMP 或 WAV,扩展名帮助得知文件类型,目录文件还存文件的元数据,比如创建时间,最后修改时间,文件所有者是谁,是否能读/写或读写都行。最重要的是,目录文件有文件起始位置和长度,如果要添加文件,删除文件,更改文件名等,必须更新目录文件。文件系统专门负责管理文件,刚刚的例子叫”平面文件系统“,因为文件都在同一个层次。
- 为了避免覆盖,现代文件系统会做两件事,1. 把空间划分成一块块,导致有一些 “预留空间”,可以方便改动同时也方便管理,目录文件要记录文件在哪些块里。2. 拆分文件,存在多个块里。只要分配块,文件可以轻松增大缩小。假设想删掉 carrie.bmp,只需要在目录文件删掉那条记录,让一块空间变成了可用,注意这里没有擦除数据,只是把记录删了,之后某个时候,那些块会被新数据覆盖,但在此之前,数据还在原处,所以计算机取证团队可以”恢复”数据。
- 碎片是增/删/改文件导致的,不可避免,计算机会把数据来回移动,排列成正确的顺序。容量爆炸式增长,文件数量也飞速增长很快,所有文件都存在同一层变得不切实际,然后文件夹套文件夹。这叫”分层文件系统“最大的变化是目录文件不仅要指向文件,还要指向目录。我们需要额外元数据来区分开文件和目录,这个目录文件在最顶层,因此叫根目录。所有其他文件和文件夹,都在根目录下。
- 如果想把 theme.wav 从根目录移到音乐目录不用移动任何数据块只需要改两个目录文件,一个文件里删一条记录,另一个文件里加一条记录theme.wav 依然在块5。文件系统使我们不必关心文件在磁带或磁盘的具体位置,整理和访问文件更加方便,我们像普通用户一样直观操纵数据,比如打开和整理文件。