计算机是如何存储数据的?

3,579 阅读5分钟

为什么需要知道

我一个前端为什么需要知道这些东西。我想,这取决于你如何定义前端。如果定义是写页面的、切图的,那或许确实没必要;但如果你定义为程序员,那这就是必要的。

To be a programmer,before you are a Front Ender.So that you won't be a frog trapped in the browser.         ---LiuYiBi

尽管我们的大部分工作都是在浏览器的层面上开发,但你知道你let了一个变量之后是如何存在你的计算机中吗,你知道你的浏览器是如何接受到你请求的网页内容吗。基于这些,你要的知道的是浏览器运行于操作系统之上,操作系统运行于硬件之上;数据来自于服务器。了解这些的目的是为了让自己不变成一个浏览器中的井底之蛙。

为了回答上面这个问题,至少需要先回答下面这几个问题。

如何存储0和1

由于计算机是使用二进制,那找到一个有两种不同状态的介质就可以存储一个比特(数据位)的数据。可以简单理解为灯泡的开闭状态,开表示1,关闭表示0。我们一般买电脑的时候会留意处理器的频率是多少赫兹,这个赫兹在这里也就意味着,刷新小灯泡状态的速度是怎样的,当然是越快越好。 具体技术上的实现是有一个称为动态随机存取存储器(Dram)的东西实现。

主要的作用原理是利用电容内存储电荷的多寡来代表一个二进制比特是1还是0。 ---维基百科

https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2019/5/26/16af46c207da9ab8~tplv-t2oaga2asx-image.image

如何存储数字

我们都知道,任何数据在计算机上都只是一串01,所以我们所熟知的十进制会被转换为二进制,37(10)=100101(2)。

简单说下进制之间的转换,以二进制转十进制为例,分别计算各数字位上2需要相乘的数量再各自相加,若当前位存在1则计算,2^5 + 0 + 0 + 2^2 + 0 + 1 = 37。另外,还有补码和浮点数为了解决负数和小数的问题。

如何存储字符

这里的字符应该简单理解为abcd这样的英文字符。最终存储的当然还是01,因此这里需要使用ASCii对应规则,其实就是一个映射,考虑到计算机只认01,那我们只需要规定一个字符对应一个AScii值,而一个ASCii又对应一串二进制数字。比如,a在AScii码表中对应的值是97(10),那么只需要a => 97(10) => 0110 0001(2),这样就把a这个字符存入了电脑中。

如何存储中文

英文倒好,全部单词都是由26个字母组合而成,但中文汉字却不一样,每个汉字都是独立的个体,在存储上无法复用。因此有了GB2312(国标),其中共有6736个汉字,因为这么多的汉字已经大大的超过了一个字节的容量。一个字节的容量即2^8,一个字节由八个二进制位构成,前面说到AScii码表,只要一个字节就可以存储所有的字符,但中文却需要两个字节,即16位。因此在一样的容量限制下,相较于汉字电脑能容纳下更多的英文字符。

汉字和字符的比较

如何存储所有字符

全球有那么多国家,有那么多不同的语言,即意味着各式的字符存在。存储地球上所有字符的解决方案是Unicode字符集。Unicode使用了4个字节(即32位,2^32)来满足存储所有字符的需求,这也导致了Unicode会浪费存储空间,因为在你存一个字母的时候是完全不需要4个字节的。

Unicode现在最新的版本(2019.3.5)已经收录了13万个字符。包括颜文字(^_^)和绘文字(🔞)。

如何将Unicode存到计算机中

如何存的问题其实在上面的回答中都已经得到解决,但如何高性价比的存又是另外一个问题。UTF-8的出现解决了这个问题。

UTF-8是一种编码的实现方式,不是字符集。一个字符的编码是确定的。

  1. 对于UTF-8编码中的任意字节B,如果B的第一位为0,则B独立的表示一个字符(ASCII码)
  2. 如果B的第一位为1,第二位为0,则B为一个多字节字符中的一个字节(非ASCII字符)
  3. 如果B的前两位为1,第三位为0,则B为两个字节表示的字符中的第一个字节
  4. 如果B的前三位为1,第四位为0,则B为三个字节表示的字符中的第一个字节
  5. 如果B的前四位为1,第五位为0,则B为四个字节表示的字符中的第一个字       --- 维基百科
# 如果直接使用UTF-32的编码存储
a => 00000000 00000000 00000000 01100001(2)
你 => 00000000 00000000 01001111 01100000(2)
# 从上面可以非常明显的看出,'a'编码的前三个字节是浪费的,
# '你'的前两个字是浪费的。

#UTF-8的解决方式
a => 01100001
你 => 11100100 10111101 10100000
# 对于英文字符的编码仍然采用ASCii的方式,
# 对于超过1个字节的,拆分表示,具体见下图。

比较
下面编码左边的1110表示有三个字节,接下来的字节由10开始。剩下的位子就按466的格式依次放到对应的位置中。这样在存的时候就省了一个字节。

谢谢看完,多多指点,欢迎点赞^_^