字符编码与文件

  • 一个在重写tcmu读写接口时遇到的问题:如何转化标准的块设备读写缓冲区?
  • 由于最初不理解相关数据底层编码方式,导致开发过程效率低下。
  • 在此总结编码相关和文件数据相关的基础知识。

字符编码与文件

字符编码

ASCII

基本概念

  • American Standard Code for Information Interchange 是基于拉丁字母的一套电脑编码系统。它主要用于显示现代英语,而其扩展版本EASCII則可以部分支持其他西欧语言,并等同于国际标准ISO/IEC 646。
  • ASCII 由电报码发展而来。至今为止共定义了128个字符;其中33个字符无法显示(一些终端提供了扩展,使得这些字符可显示为诸如笑脸、扑克牌花式等8-bit符号),且这33个字符多数都已是陈废的控制字符。控制字符的用途主要是用来操控已经处理过的文字。在33个字符之外的是95个可显示的字符。用键盘敲下空白键所产生的空白字符也算1个可显示字符(显示为空白)。

组成

  • 对应十进制编码为 0-31 的是 ASCII 控制字符,127 也为控制字符。
    • 控制字符主要表现为无法在进行正确的格式化输出,往往会因为终端机的环境不同,显示方式也会有所区别。
  • 对应十进制编码为 32-126 的是 可显示字符。其中:
    • 数字1 对应编码 49(10进制)
    • 字母A 对应编码 65
    • 字母a 对应编码 97

应用

缺陷

  • ASCII的局限在于只能显示26个基本拉丁字母、阿拉伯数字和英式标点符号,因此只能用于显示现代美国英语(且处理naïve、café、élite等外来语时,必须去除附加符号)。虽然EASCII解决了部分西欧语言的显示问题,但对更多其他语言依然无能为力。因此,现在的软件系统大多采用Unicode。

Base64

概念

  • Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于 { 2^6=64,所以每6个位元为一个单元,对应某个可打印字符。3个字节有24个位元,对应于4个Base64单元,即3个字节可由4个可打印字符来表示。

组成

  • 在Base64中的可打印字符包括字母A-Z、a-z、数字0-9,这样共有62个字符,此外两个可打印符号在不同的系统中而不同。一般情况下另外两个字符为 + 和 /。
  • 经过 Base64 编码之后的字符,长度将会有所增加。对应的关系为 原字符长度除以3 之后向上取整(字节补位变成3的倍数),然后再乘以四得到对应的编码之后的长度。

应用

  • Base64常用于在通常处理文本数据的场合,表示、传输、存储一些二进制数据,包括MIME的电子邮件及XML的一些复杂数据;
  • Base64编码可用于在HTTP环境下传递较长的标识信息,常用于URL的编码,但由于 = + / 这三种符号在URL中有自己独特的语义,所以需要对标准的 Base64 编码算法进行改进,将这些符号进行替换。

计算方式

  • 如果要编码的字节数不能被3整除,最后会多出1个或2个字节,那么可以使用下面的方法进行处理:先使用0字节值在末尾补足,使其能够被3整除,然后再进行Base64的编码。在编码后的Base64文本后加上一个或两个=号,代表补足的字节数。也就是说,当最后剩余两个八位字节(2个byte)时,最后一个6位的Base64字节块有四位是0值,最后附加上两个等号;如果最后剩余一个八位字节(1个byte)时,最后一个6位的base字节块有两位是0值,最后附加一个等号。 参考下表:
    image

Unicode

概念

  • Unicode(中文:万国码、国际码、统一码、单一码)是计算机科学领域里的一项业界标准。它对世界上大部分的文字系统进行了整理、编码,使得计算机可以用更为简单的方式来呈现和处理文字。
  • Unicode备受认可,并广泛地应用于计算机软件的国际化与本地化过程。有很多新科技,如可扩展置标语言(Extensible Markup Language,简称:XML)、Java编程语言以及现代的操作系统,都采用Unicode编码。
  • Unicode 主要做的工作就是将世界上所有的语言都统一到一套编码里,从而解决乱码问题。

组成

  • Unicode标准也在不断发展,但最常用的是用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。现代操作系统和大多数编程语言都直接支持Unicode。
  • ASCII编码是1个字节,而Unicode编码通常是2个字节

痛点

  • 如果你写的文本基本上全部是英文的话,用Unicode编码比ASCII编码需要多一倍的存储空间,在存储和传输上就十分不划算。从而推出了可变长编码 UTF-8。

UTF-8

  • UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4-6个字节。如果你要传输的文本包含大量英文字符,用UTF-8编码就能节省空间
  • 由于UTF-8存在单字节编码,所以UTF-8能兼容ASCII码
  • 在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。
实例 - 记事本
  • 用记事本编辑的时候,从文件读取的UTF-8字符被转换为Unicode字符到内存里,编辑完成后,保存的时候再把Unicode转换为UTF-8保存到文件:
实例 - 浏览器
  • 浏览网页的时候,服务器会把动态生成的Unicode内容转换为UTF-8再传输到浏览器,所以你看到很多网页的源码上会有类似的信息,表示该网页正是用的UTF-8编码。

UTF-32

  • UTF-32 是固定长度的编码,始终占用 4 个字节,足以容纳所有的 Unicode 字符,所以直接存储 Unicode 编号即可,不需要任何编码转换。浪费了空间,提高了效率。

UTF-16

  • 对于 Unicode 编号范围在 0 ~ FFFF 之间的字符,UTF-16 使用两个字节存储,并且直接存储 Unicode 编号,不用进行编码转换,这跟 UTF-32 非常类似。
  • 对于 Unicode 编号范围在 10000~10FFFF 之间的字符,UTF-16 使用四个字节存储,具体来说就是:将字符编号的所有比特位分成两部分,较高的一些比特位用一个值介于 D800~DBFF 之间的双字节存储,较低的一些比特位(剩下的比特位)用一个值介于 DC00~DFFF 之间的双字节存储。

文件

  • 计算机的存储在物理上是二进制的,所以文本文件与二进制文件的区别并不是物理上的,而是逻辑上的。这两者只是在编码层次上有差异。(严格意义上,文本文件也是二进制文件)
  • 简单来说,文本文件是基于字符编码的文件,常见的编码有ASCII编码,UNICODE编码等等。二进制文件是基于值编码的文件。

文本文件

  • 文本文件是一种计算机文件,它是一种典型的顺序文件,其文件的逻辑结构又属于流式文件。
  • 文本文件是指以ASCII码方式(也称文本方式)存储的文件,更确切地说,英文、数字等字符存储的是ASCII码,而汉字存储的是机内码。文本文件中除了存储文件有效字符信息(包括能用ASCII码字符表示的回车、换行等信息)外,不能存储其他任何信息。

二进制文件

  • 文件在外部设备的存放形式为二进制而得名。狭义的二进制文件即除文本文件以外的文件。
  • 二进制文件可看成是变长编码的,因为是值编码,多少个比特代表一个值,完全由自己决定。

优势

  • 二进制文件比较节约空间,这两者储存字符型数据时并没有差别,但是在储存数字,特别是实型数字时,二进制更节省空间。
  • 内存中参加计算的数据都是用二进制无格式储存起来的,因此,使用二进制储存到文件就更快捷
  • 一些比较精确的数据,使用二进制储存不会造成有效位的丢失。

对比

相同

  • 文件在磁盘上的存储方式都是二进制形式。但二进制读写是将内存里面的数据直接读写入文本中,而文本呢,则是将数据先转换成了字符串,再写入到文本中。
  • 组成:控制信息和内容信息。 (文本文件不包含控制信息)

不同

  1. 能存储的数据类型不同:文本文件只能存储char型字符变量。二进制文件可以存储char/int/short/long/float/……各种变量值。
  2. 每条数据的长度:文本文件每条数据通常是固定长度的。以ASCII为例,每条数据(每个字符)都是1个字节。进制文件每条数据不固定。如short占两个字节,int占四个字节,float占8个字节……
  3. 读取的软件不同:文本文件编辑器就可以读写。比如记事本、NotePad++、Vim等。二进制文件需要特别的解码器。比如bmp文件需要图像查看器,rmvb需要播放器……
  4. 操作系统对换行符('\n')的处理不同(不重要):文本文件,操作系统会对'\n'进行一些隐式变换,因此文本文件直接跨平台使用会出问题。二进制文件,操作系统不会对'\n'进行隐式变换,很多二进制文件(如电影、图片等)可以跨平台使用。

参考文献