ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

从0和1到屏幕:计算机如何存储文字、图像、音频与视频

从0和1到屏幕:计算机如何存储文字、图像、音频与视频 计算机里的一切文字、图片、音乐、视频归根结底都只是一串由0和1组成的二进制数字。这个结论很多人听过但真正能把它讲清楚、讲透的人并不多。我做了十多年底层开发和系统相关的工作面试过不少候选人发现一个很普遍的现象大家都能背出计算机存储的是二进制但一旦追问一张图片是怎么变成二进制的为什么同一个视频文件在不同设备上显示效果不一样像素到底是什么能答上来的人就少了一大半。这篇内容就是想把这条链路从头到尾捋一遍从最底层的比特和字节到文字编码、图像像素、音频采样、视频帧再到最终在屏幕上显示出来的整个过程。不管你是刚学计算机组成原理的学生还是工作几年想补补基础的开发者或者只是单纯好奇电脑到底怎么记住我拍的照片的普通人这篇内容都能让你有一个清晰、完整的认知。1. 从比特到字节计算机存储的最小单位到底是什么1.1 为什么计算机偏偏选了二进制要理解存储得先理解为什么是二进制而不是十进制或者别的什么进制。这个问题看似基础但它是整条链路的起点。计算机的底层是晶体管和电路。一个电路最稳定的两种状态就是通电和断电或者更准确地说是高电平和低电平。用这两种状态来表示信息抗干扰能力最强电路设计也最简单。如果要用十进制那就意味着一个存储单元需要区分十种不同的电压等级这在工程上极其困难稍微有点电压波动就会读错。二进制只有两个状态容错空间大得多。所以计算机选择二进制不是因为它高级恰恰是因为它简单可靠。这一点很关键很多初学者会觉得二进制是某种高深的设计其实它是最朴素、最工程化的选择。一个二进制位也就是一个bit只能表示0或1两种状态。这太少了表示一个字母都不够。于是我们把8个bit打包成一组叫做一个字节Byte。一个字节可以表示2的8次方也就是256种不同的组合。这就是计算机存储的基本单位。1.2 字节、KB、MB这些单位是怎么换算的很多人对存储单位的换算有模糊的认识知道1KB等于1024字节但说不清为什么是1024而不是1000。原因还是二进制。1024是2的10次方。计算机的寻址和存储天然以2的幂次来组织所以用1024作为进位比1000更自然。下面这张表把常见单位理清楚单位换算关系实际字节数1 Byte8 bit81 KB1024 Byte10241 MB1024 KB10485761 GB1024 MB10737418241 TB1024 GB1099511627776注意硬盘厂商在标注容量时通常用1000进位而操作系统用1024进位这就是为什么你买了一块500GB的硬盘系统里显示只有465GB左右。这不是硬盘缩水而是换算标准不同。理解了比特和字节后面所有的内容才有根基。文字、图像、音频、视频不管多复杂最终都要被拆解成一个个字节存到存储介质上。1.3 存储介质是怎么保存这些0和1的字节是逻辑单位但物理上它得有个地方待着。不同的存储介质保存0和1的方式完全不同。机械硬盘HDD靠磁性材料的磁化方向来记录。一个微小的磁畴磁化方向朝上代表1朝下代表0。读写磁头飞过盘片表面改变或读取这些磁畴的方向。这也是为什么机械硬盘怕摔磁头和盘片之间的距离极小震动可能导致物理损伤。固态硬盘SSD靠浮栅晶体管里的电荷来记录。有没有电荷、电荷量多少对应不同的状态。现在主流的TLC、QLC颗粒一个存储单元能存3个甚至4个bit靠的就是精确控制电荷量的不同等级。内存RAM靠电容的充放电来记录电容有电代表1没电代表0。但电容会漏电所以内存需要不断刷新断电后数据就没了这就是内存和硬盘最本质的区别。U盘、SD卡本质上和SSD类似都是闪存技术。光盘则是靠表面的凹凸坑来记录激光反射的差异被解读为0和1。不管哪种介质核心逻辑都一样找到一种物理方式能稳定地表示两种状态然后大规模地组织起来。2. 文字是怎么变成一串数字的编码的来龙去脉2.1 ASCII最早的文字编码方案文字要存储第一步是给每个字符分配一个数字编号这个编号就是编码。最早的编码方案是ASCII美国信息交换标准代码。它用7个bit也就是0到127来表示128个字符。其中包括26个大写字母、26个小写字母、10个数字、各种标点符号以及一些控制字符。比如大写字母A的ASCII码是65小写a是97数字0是48。这些数字你不需要死记但理解它的存在很重要计算机里根本没有字母A这个东西它存的只是数字65显示的时候查表发现65对应A才画出一个A来。ASCII的问题很明显它只能表示英文和少量符号中文、日文、阿拉伯文统统表示不了。7个bit最多128个字符就算扩展到8个bit也才256个远远不够。2.2 中文编码的曲折历程中文有几千个常用汉字256个位置根本不够用。所以中文必须用多个字节来编码。最早的中文编码方案是GB2312用两个字节表示一个汉字收录了6763个汉字。后来扩展到GBK收录了两万多个汉字再后来是GB18030收录了七万多个。但问题来了GB2312、GBK、GB18030都是中国自己的标准日本有Shift-JIS韩国有EUC-KR欧洲有ISO-8859系列。每个地区一套标准互相不兼容。你用GBK编码保存的中文文件拿到用Shift-JIS编码的系统上打开就会变成一堆乱码。这就是为什么早些年打开一些老网页或者老文件经常看到锟斤拷这种乱码。本质上是编码和解码用了不同的字符集。2.3 Unicode和UTF-8统一编码的解决方案为了解决乱码问题Unicode诞生了。它的目标很简单给全世界所有的字符包括各种语言的文字、符号、emoji都分配一个唯一的编号。这个编号叫做码点Code Point。比如汉字中的Unicode码点是U4E2D字母A是U0041。Unicode只是一个字符集它规定了每个字符对应的编号但没有规定这个编号怎么存成字节。UTF-8就是Unicode的一种存储实现方式。它的特点是变长编码英文字符用1个字节中文用3个字节emoji用4个字节。这样做的好处是兼容ASCII同时节省空间。字符Unicode码点UTF-8编码十六进制占用字节AU0041411中U4E2DE4 B8 AD3U1F600F0 9F 98 804提示现在做开发文本文件一律用UTF-8编码基本可以避免99%的乱码问题。如果遇到乱码第一件事就是检查编码格式是否一致。2.4 一个汉字在内存里到底长什么样举个具体的例子。汉字中用UTF-8编码是三个字节E4 B8 AD。转成二进制就是E4 11100100B8 10111000AD 10101101所以中这个字在内存里实际存储的就是这24个bit111001001011100010101101。当程序要显示这个字的时候它会读取这24个bit识别出这是一个UTF-8编码的三字节序列查表找到对应的Unicode码点U4E2D然后从字体文件中找到这个码点对应的字形最后把字形画到屏幕上。整个过程涉及编码、解码、字体渲染多个环节任何一个环节出错你看到的就不是中而是乱码或者方块。3. 图像存储的核心像素、颜色和压缩3.1 像素到底是什么图像在计算机里的存储核心概念是像素。像素是图像的最小单位你可以把它理解成一张网格上的一个小格子每个格子有自己的颜色。一张1920x1080的图片意思就是横向有1920个像素纵向有1080个像素总共约207万个像素。每个像素都需要存储颜色信息。那颜色怎么存最常见的方式是RGB模型。每个像素用三个数值表示红Red、绿Green、蓝Blue三个通道的强度每个通道通常用8个bit也就是0到255。比如纯红色是(255, 0, 0)纯白色是(255, 255, 255)纯黑色是(0, 0, 0)。三个通道各8bit一个像素就是24bit也就是3个字节。一张1920x1080的未压缩图片大小就是207万乘以3字节约6.2MB。这就是为什么未经压缩的图片文件那么大。3.2 分辨率、位深度和颜色数量理解图像存储有几个参数必须搞清楚分辨率决定了图像的像素总数。分辨率越高细节越丰富但文件也越大。位深度决定了每个像素能表示多少种颜色。8位就是256色24位就是1677万色俗称真彩色32位通常是在24位基础上加了一个8位的透明度通道Alpha通道。位深度每像素字节数可表示颜色数典型用途8位1256早期图标、简单图形16位265536部分游戏贴图24位3约1677万普通照片、网页图片32位4约1677万透明度PNG图片、UI设计注意位深度和分辨率是独立的。一张高分辨率但低位深的图片可能很大但颜色很单调一张低分辨率高位深的图片可能很小但色彩丰富。3.3 有损压缩和无损压缩的本质区别未压缩的图片太大了所以实际使用中几乎都会压缩。压缩分两大类无损和有损。无损压缩的代表是PNG。它通过算法找出图像中的冗余信息比如大片相同颜色的区域用更紧凑的方式记录。解压后能完全还原原始数据一个bit都不差。适合需要精确还原的场景比如截图、图标、线条图。有损压缩的代表是JPEG。它利用了人眼对某些细节不敏感的特性主动丢弃一部分信息。比如把高频的细节模糊掉因为人眼对大面积的颜色变化敏感对细微的纹理变化不敏感。JPEG可以把图片压缩到原大小的十分之一甚至更小但反复编辑保存会越来越模糊。这里有个很多人踩过的坑把一张JPEG图片反复打开、编辑、保存每次都会重新压缩画质会累积性下降。正确做法是编辑时保存为PNG或PSD等无损格式最终输出时再转成JPEG。3.4 从文件到屏幕图像显示的完整链路一张图片从文件到显示在屏幕上经历的过程比大多数人想象的复杂。第一步程序读取图片文件根据文件头识别格式PNG还是JPEG还是别的。第二步按照对应格式的解码算法把压缩数据还原成像素数据。这一步得到的是一个像素数组每个像素包含RGB值。第三步像素数据被送到显卡。显卡根据当前显示器的分辨率、缩放比例决定每个像素应该画在屏幕的哪个位置。如果图片分辨率和屏幕分辨率不一致还需要进行缩放插值。第四步显卡把每个像素的颜色值转换成显示器能理解的信号。LCD屏幕的每个像素实际上是由红绿蓝三个子像素组成的通过控制每个子像素的透光率混合出目标颜色。第五步显示器的驱动电路逐行扫描把每个像素的颜色点亮你的眼睛就看到了一整张图片。这个链路里任何一个环节的参数不匹配都可能导致显示异常。比如颜色空间不一致会导致偏色缩放算法不好会导致图片模糊或锯齿。4. 音频和视频时间维度上的存储挑战4.1 声音是怎么被数字化成二进制声音本质上是空气的振动是一种连续的模拟信号。计算机要存储它必须把它变成离散的数字这个过程叫采样。采样的逻辑是每隔一个固定的时间间隔测量一次声音的振幅把测量结果用一个数字记录下来。这个时间间隔的倒数就是采样率。最常见的采样率是44100Hz也就是每秒采样44100次。这个数字不是随便定的它来自奈奎斯特采样定理要完整还原一个频率为f的信号采样率必须至少是2f。人耳的听觉上限大约是20000Hz所以采样率至少要40000Hz44100Hz是一个留了余量的工程选择。每次采样的结果用一个数字表示这个数字的位数就是位深度。16bit位深度意味着每次采样的振幅可以用0到65535之间的一个整数表示。所以一段CD音质的音频每秒的数据量是44100次采样 × 2个声道 × 2字节 176400字节约172KB每秒。一首4分钟的歌曲未压缩大约40MB。4.2 音频压缩为什么能大幅减小文件未压缩音频太大了所以需要压缩。音频压缩同样分有损和无损。无损压缩比如FLAC能压缩到原大小的50%到70%解压后完全还原。有损压缩比如MP3和AAC利用了心理声学模型。简单说人耳在某些频率的声音存在时对附近其他频率的声音不敏感这些被掩蔽的声音就可以大胆丢弃。MP3可以把音频压缩到原大小的十分之一甚至更小普通人很难听出明显差异。提示如果你做音频相关的开发采样率和位深度是两个必须明确的参数。采样率决定了能还原的最高频率位深度决定了动态范围。搞错任何一个音频质量都会出问题。4.3 视频存储一帧一帧的图片加上声音视频的本质是一连串快速播放的图片加上同步的音频。每一张图片叫一帧。常见的视频帧率是24帧每秒电影、25帧每秒PAL制式电视、30帧每秒NTSC制式电视或60帧每秒高帧率视频。人眼大约在每秒16帧以上就会感觉是连续运动。如果视频只是简单地把每一帧都存成一张图片那文件会大到无法接受。一段1080p、30帧每秒、1分钟的视频如果每帧都存成未压缩图片大小约为6.2MB × 30 × 60超过11GB。所以视频压缩的核心思路是不存每一帧的完整画面只存帧与帧之间的差异。大部分相邻帧的内容是相似的只有运动的部分在变化。视频编码器会计算出这些差异只记录变化的部分。这就是为什么视频压缩比图片压缩复杂得多也是为什么视频编码格式H.264、H.265、AV1等的算法如此庞大。4.4 视频播放时解码器在做什么当你播放一个视频文件时播放器做的事情大致如下首先分离器把视频文件拆分成视频流和音频流。视频文件通常是一个容器格式比如MP4、MKV里面封装了视频编码数据和音频编码数据。然后视频解码器读取视频流按照编码格式的规则把压缩数据还原成一帧一帧的图片。这个过程需要大量的计算尤其是高分辨率高帧率的视频。同时音频解码器把音频流还原成PCM采样数据。接着播放器需要做音视频同步。因为视频解码和音频解码的速度可能不一样必须保证画面和声音对得上。通常以音频时钟为基准视频帧根据音频的播放进度来调整显示时机。最后解码后的视频帧被送到显卡渲染音频采样被送到声卡播放。这个链路里解码器的性能、显卡的渲染能力、音频输出的延迟都会影响最终的观看体验。这也是为什么同样的视频文件在不同设备上播放流畅度差别很大。5. 显示环节二进制数据如何变成你看到的画面5.1 显卡和显示器之间的分工很多人以为显示器负责显示显卡负责计算这个理解大致对但细节值得说清楚。显卡GPU的核心工作是接收应用程序传来的图像数据进行必要的计算和变换然后输出一个最终的像素矩阵。这个矩阵里每个像素都有明确的颜色值。显示器的工作是接收显卡输出的信号把每个像素的颜色值转换成实际的光。LCD显示器通过控制液晶分子的偏转来调节背光的透过率OLED显示器则直接控制每个像素的发光。显卡和显示器之间通过接口传输数据常见的有HDMI、DisplayPort、USB-C等。接口的带宽决定了能支持的最大分辨率和刷新率。比如4K 60Hz需要的带宽比1080p 60Hz高得多老旧的接口可能带不动。5.2 像素在屏幕上是如何被点亮的以LCD屏幕为例每个像素实际上由三个子像素组成一个红色、一个绿色、一个蓝色。每个子像素的透光率可以独立控制。当显卡告诉显示器某个像素应该是(255, 128, 0)这个颜色时显示器会把红色子像素开到最大绿色子像素开到约一半蓝色子像素完全关闭。三个子像素的光混合在一起人眼看到的就是橙色。因为子像素非常小正常观看距离下人眼无法分辨单个子像素看到的是混合后的颜色。这就是为什么屏幕能显示出丰富的色彩。注意如果你用手机微距拍摄屏幕会看到红绿蓝的小点那就是子像素。这也是为什么有些屏幕在显示纯色时边缘会有轻微的彩边那是子像素排列方式导致的。5.3 刷新率和响应时间对显示效果的影响刷新率是屏幕每秒重绘画面的次数单位是Hz。60Hz意味着每秒刷新60次144Hz意味着每秒刷新144次。刷新率越高画面越流畅尤其是快速运动的场景。但刷新率也受限于显卡的输出能力和接口的带宽。响应时间是像素从一种颜色变到另一种颜色所需的时间单位通常是毫秒。响应时间越短快速运动时的拖影越少。这两个参数经常被混淆但它们描述的是不同的东西。刷新率是多久画一次响应时间是画一次多快能到位。5.4 为什么同一个文件在不同设备上显示效果不同这是一个非常实际的问题。同一个图片或视频文件在手机、电脑、电视上看起来可能颜色、亮度、对比度都不一样。原因有很多第一不同设备的屏幕面板不同。IPS、VA、OLED的色域、对比度、可视角度都不一样。第二不同设备的色彩管理不同。有的设备会自动调整色彩有的不会。专业显示器通常支持色彩校准消费级设备则各有各的调法。第三不同设备的解码和渲染管线不同。同一个视频手机可能用硬件解码电脑可能用软件解码渲染出来的效果可能有细微差异。第四环境光的影响。同样的屏幕在明亮的户外和昏暗的室内看起来完全不同。所以如果你做设计或者视频剪辑专业显示器加色彩校准是必须的。普通用户如果发现不同设备显示效果差异大大概率是色彩管理的问题不是文件本身的问题。6. 实操中容易踩的坑和排查思路6.1 乱码问题的排查链路乱码是最常见的存储和显示问题之一。遇到乱码不要慌按下面的链路排查第一步确认原始文件的编码格式。如果是文本文件可以用十六进制编辑器查看前几个字节判断是否有BOM头。UTF-8的BOM是EF BB BFUTF-16的BOM是FF FE或FE FF。第二步确认打开文件的程序用的什么编码。很多编辑器可以手动切换编码试试GBK、UTF-8、Latin-1等常见编码看哪个能正常显示。第三步如果是网页乱码检查HTML的meta标签里charset是否正确以及服务器返回的Content-Type头里的charset。第四步如果是数据库乱码检查数据库、表、连接三个层级的字符集设置是否一致。这三者任何一个不一致都可能导致乱码。我踩过最坑的一次是数据库连接字符串里没指定字符集导致写入的中文全部变成了问号。排查了半天才发现是连接层的问题。6.2 图片显示异常的常见原因图片显示异常通常有几种表现显示不出来、显示成方块、颜色不对、模糊。显示不出来先检查文件路径和权限再检查文件是否损坏。可以用十六进制编辑器看文件头PNG的文件头是89 50 4E 47JPEG的文件头是FF D8 FF。显示成方块通常是字体问题。如果程序需要显示某个字符但字体里没有这个字形就会显示成方块或问号。颜色不对检查色彩空间。sRGB和Adobe RGB是不同的色彩空间混用会导致偏色。模糊检查缩放算法和原始分辨率。如果图片被放大超过原始分辨率模糊是必然的。6.3 音视频不同步的排查思路音视频不同步是播放器开发中的经典问题。排查思路如下首先确认是音频快了还是视频快了。如果是音频快了可能是音频时钟走得太快如果是视频快了可能是视频解码或渲染太慢。然后检查时间戳。音视频流里都有时间戳播放器根据时间戳来同步。如果时间戳本身有问题同步就无从谈起。接着检查解码性能。如果视频解码耗时超过了帧间隔视频就会落后。可以降低分辨率或换用硬件解码来验证。最后检查缓冲策略。播放器通常会缓冲一定量的数据再开始播放缓冲策略不当也会导致同步问题。6.4 存储空间计算的实用技巧做开发时经常需要估算存储空间。这里分享几个实用技巧图片存储估算宽度 × 高度 × 每像素字节数。24位色就是3字节32位色就是4字节。再根据压缩率打个折JPEG通常可以压到10%到20%PNG通常可以压到30%到70%。音频存储估算采样率 × 位深度 ÷ 8 × 声道数 × 时长。比如44100Hz、16bit、双声道、60秒就是44100 × 2 × 2 × 60 10584000字节约10MB。视频存储估算这个比较复杂因为压缩率取决于内容。一般来说1080p视频的码率在5Mbps到10Mbps之间4K视频在20Mbps到50Mbps之间。用码率乘以时长就能估算大小。提示估算时留20%到30%的余量因为文件头、元数据、封装格式都会占用额外空间。7. 把这些知识串起来一个完整的案例7.1 从拍照到看到照片的完整旅程让我们用一个具体的场景把所有知识串起来你用手机拍了一张照片然后在电脑上打开它。拍照时手机摄像头的传感器把光信号转换成电信号再经过模数转换变成数字信号。每个像素的颜色值被记录下来通常还会经过一些图像处理比如降噪、锐化、色彩校正。然后照片被编码成JPEG格式。编码器把像素数据分成8x8的块做离散余弦变换量化再熵编码最终生成一个压缩后的文件。同时照片的元数据拍摄时间、地点、相机型号等被写入EXIF信息。照片保存到手机的存储里可能是UFS闪存。闪存控制器把数据写入浮栅晶体管完成物理存储。你把照片传到电脑上电脑的图片查看器读取文件识别出是JPEG格式调用JPEG解码器还原出像素数据。像素数据被送到显卡显卡根据窗口大小和屏幕分辨率进行缩放输出最终的像素矩阵。显示器接收信号控制每个像素的红绿蓝子像素把照片显示出来。你的眼睛看到照片大脑识别出这是你拍的那只猫。整个过程涉及光学、电子、编码、存储、渲染、显示多个领域但底层逻辑是一致的一切都是0和1的组织和变换。7.2 理解这条链路对实际工作的价值可能有人会问我又不做底层开发理解这些有什么用用处比你想的大。遇到乱码你知道去查编码图片模糊你知道去查分辨率和缩放视频卡顿你知道去查解码性能存储空间不够你知道怎么估算和优化。更重要的是理解这条链路能帮你建立一种分层的思维方式。计算机系统是层层抽象的每一层解决特定问题向上提供接口向下依赖支撑。理解了这种分层结构学习任何新技术都会更快因为你总能把它放到已有的知识框架里。7.3 几个值得深入的方向如果你对这块内容感兴趣有几个方向值得深入字符编码方向可以研究Unicode的完整规范包括各种 normalization 形式和 collation 算法。图像处理方向可以研究各种压缩算法的数学原理比如DCT、小波变换。音视频方向可以研究H.264/H.265的编码细节或者自己写一个简单的播放器。存储方向可以研究文件系统的实现比如ext4、NTFS、APFS的设计差异。显示方向可以研究色彩管理、HDR、广色域等技术。每一个方向都足够深足够你钻研很多年。但不管走多深底层的逻辑始终是那一条把信息变成0和1存起来再还原出来。我在实际工作中最大的体会是很多看似复杂的问题追到根上都是基础概念没搞清楚。比如有人调了半天视频同步最后发现是时间戳的单位搞错了有人折腾半天图片颜色最后发现是色彩空间没转换。基础扎实了排查问题的速度会快很多因为你知道该往哪个方向找。最后分享一个小技巧遇到任何存储或显示相关的问题先用十六进制编辑器打开文件看看原始数据。很多时候看一眼原始字节比看十篇文档都管用。数据不会骗人它就在那里等着你去解读。
返回列表