1、为什么需要编码
计算机中存储信息的最小单元是一个字节即 8 个 bit,所以能表示的字符范围是 0~255 个;人类要表示的符号太多,无法用一个字节来完全表示;要解决这个矛盾必须需要一个新的数据结构 char,从 char 到 byte 必须编码。
2、各种常见编码的简介
- ASCII 码
学过计算机的人都知道 ASCII 码,总共有 128 个,用一个字节的低 7 位表示,0~31 是控制字符如换行回车删除等;32~126 是打印字符,可以通过键盘输入并且能够显示出来。
- ISO-8859-1
128 个字符显然是不够用的,于是 ISO 组织在 ASCII 码基础上又制定了一些列标准用来扩展 ASCII 编码,它们是 ISO-8859-1~ISO-8859-15,其中 ISO-8859-1 涵盖了大多数西欧语言字符,所有应用的最广泛。ISO-8859-1 仍然是单字节编码,它总共能表示 256 个字符。
- GB2312
它的全称是《信息交换用汉字编码字符集 基本集》,它是双字节编码,总的编码范围是 A1-F7,其中从 A1-A9 是符号区,总共包含 682 个符号,从 B0-F7 是汉字区,包含 6763 个汉字。
- GBK
全称叫《汉字内码扩展规范》,是国家技术监督局为 windows95 所制定的新的汉字内码规范,它的出现是为了扩展 GB2312,加入更多的汉字,它的编码范围是 8140~FEFE(去掉 XX7F)总共有 23940 个码位,它能表示 21003 个汉字,它的编码是和 GB2312 兼容的,也就是说用 GB2312 编码的汉字可以用 GBK 来解码,并且不会有乱码。
- GB18030
全称是《信息交换用汉字编码字符集》,是我国的强制标准,它可能是单字节、双字节或者四字节编码,它的编码与 GB2312 编码兼容,这个虽然是国家标准,但是实际应用系统中使用的并不广泛。
- UTF-16
说到 UTF 必须要提到 Unicode(Universal Code 统一码),ISO 试图想创建一个全新的超语言字典,世界上所有的语言都可以通过这本字典来相互翻译。可想而知这个字典是多么的复杂,关于 Unicode 的详细规范可以参考相应文档。Unicode 是 Java 和 XML 的基础,下面详细介绍 Unicode 在计算机中的存储形式。
UTF-16 具体定义了 Unicode 字符在计算机中存取方法。UTF-16 用两个字节来表示 Unicode 转化格式,这个是定长的表示方法,不论什么字符都可以用两个字节表示,两个字节是 16 个 bit,所以叫 UTF-16。UTF-16 表示字符非常方便,每两个字节表示一个字符,这个在字符串操作时就大大简化了操作,这也是 Java 以 UTF-16 作为内存的字符存储格式的一个很重要的原因。
- UTF-8
UTF-16 统一采用两个字节表示一个字符,虽然在表示上非常简单方便,但是也有其缺点,有很大一部分字符用一个字节就可以表示的现在要两个字节表示,存储空间放大了一倍,在现在的网络带宽还非常有限的今天,这样会增大网络传输的流量,而且也没必要。而 UTF-8 采用了一种变长技术,每个编码区域有不同的字码长度。不同类型的字符可以是由 1~6 个字节组成。
UTF-8 有以下编码规则:
- 如果一个字节,最高位(第 8 位)为 0,表示这是一个 ASCII 字符(00 - 7F)。可见,所有 ASCII 编码已经是 UTF-8 了。
- 如果一个字节,以 11 开头,连续的 1 的个数暗示这个字符的字节数,例如:110xxxxx 代表它是双字节 UTF-8 字符的首字节。
- 如果一个字节,以 10 开始,表示它不是首字节,需要向前查找才能得到当前字符的首字节
3、JAVA中的编码场景
JAVA是使用UTF-16,也就是定长的2个字节来进行编码,例如定义int为4byte,short为2byte。因为任何字符都是2字节的最小单元表示,所以处理起来很方便,但同时也会浪费空间,有些简单的字符只需要一个字节就可以表示,其本质就是用空间换时间。
JAVA中的编码场景主要有I/O操作和内存操作
1> I/O操作
例如InputStreamReader 就是从字节流到字符流的解码过程。而具体字节到字符的解码实现它由 StreamDecoder去实现,在 StreamDecoder解码过程中必须由用户指定 Charset编码格式。值得注意的是如果你没有指定 Charset,将使用本地环境中的默认字符集,例如在中文环境中将使用 GBK 编码。
OutputStreamWriter 转换字符到字节,同样 StreamEncoder 类负责将字符编码成字节,编码格式和默认编码规则与解码是一致的。
2>内存操作
String s = "字符串。。。";
byte[] bt = s.getBytes("UTF-8");
String str = new String(bt,"UTF-8");
String 类就提供转换到字节的方法,也支持将字节转换为字符串的构造函数。
Charset 提供 encode 与 decode 分别对应 char[] 到 byte[] 的编码和 byte[] 到 char[] 的解码。如下代码所示:
Charset charset = Charset.forName("UTF-8"); ByteBuffer byteBuffer = charset.encode(string); CharBuffer charBuffer = charset.decode(byteBuffer); |
字符和字节之间的相互转换只要我们设置编解码格式统一一般都不会出现问题。
4、Java Web 涉及到的编码
a.http://code.google.com/p/protobuf/downloads/list ,选择其中的win版本下载
b.下载一个protobuf-java-version.jar文件(注意,要与你刚才下的proto.exe版本相同,否则可能出现编译通不过现象)
c. 在proto.exe同级目录,编写一个.proto文件:支持message的嵌套,对应java的内部类。
d、使用protoc命令进行编译
2>序列化和反序列化分析
1、package与optionjava_package同时存在,后者会取代前者 。
java代码生成相关参考:https://developers.google.com/protocol-buffers/docs/reference/java-generated?hl=zh-CN
2、PB数据类型
required: a well-formed message must have exactly one of this field.
optional: a well-formed message can have zero or one of this field (but not more than one).
repeated: this field can be repeated any number of times (including zero) in a well-formed message. The order of the repeated values will be preserved.
类型参考https://developers.google.com/protocol-buffers/docs/proto?hl=zh-CN&csw=1
3、message的编码特点
PB之所以解析速度快、所占体积小,很大程度上是由它序列化的编码特点来决定的。
3.1 Base 128 Varints
PB采用了Base 128 Varints来变长编码整数:
变长编码的整数,它可能包含多个byte,对于每个byte的8位,其中后7位表示数值,最高的一位表示是否还有还有另一个byte,0表示没有,1表示有;
越前面的byte表示数值的低位,越后面的byte表示数值的高位;
例子:
300 varints 编码为:1010 1100 0000 0010
解释如下:
300的2进制编码为:0001 0010 1100
按照刚才的规则,高低位颠倒,截取最后的7为放在第一个byte,则第一byte为1010 1100(其中最高位1表示,后续还有byte);接着剩下的内容放到第二个byte,为0000 0010(其中最高位0表示,后续无byte,这个数到这里截止了)。
于是,合在一起为 1010 1100 0000 0010;
PB将 key编码成下面的结构:
X YYYY ZZZ
其中:最高位X表示是否还有后续的byte来编码数字别名;YYYY用于编码别名,定义了多于16个属性,则需要用到额外的byte,所以出现频率高的字段应当取1-16的别名);ZZZ表示这个字段的类型,PB支持的属性的对应规则如下表:
3.2具体实例分析
如下图所示,针对上述定义的proto文件及序列化后的字节流进行分析
byte[0]: 10 0 0001 010 别名1,类型repeated
byte[1]: 14 一个对象所占字节数
byte[2]: 8 0 0001 000 missionId
byte[3]: 16 0 0010 000 missionUserId
byte[4]: 24 0 0011 000 status
byte[5]: 32 0 0100 000 finishedTime
PB具有跨平台、解析速度快、序列化数据体积小、扩展性高、使用简单的特点。但是我们也可以看到,相比于XML,PB的数据,并不是自然可读的;同时它生成的代码不是纯pojo,对于代码有一定的侵入性。例如pb不支持像Map<Long, 0bject>,其中Object会出现多种不确定的类型,这样就无法通过pb序列化。从上述分析的数据可以看出,protobuf采用的k-v存储结构,并且采用变长的字节编码格式,所以从空间效率比较高。
相关推荐
5. **protobuf与JSON互操作**:protobuf还支持与JSON格式的互换,这在API接口或者需要人类可读格式时非常有用。可以使用`JsonFormat`类进行JSON与protobuf对象之间的转换。 6. **protobuf扩展性**:protobuf支持可...
4. **使用ProtoBuf与Netty集成** `HelloNetty`可能是一个示例项目,展示如何在使用Netty框架的网络应用中利用ProtoBuf进行数据传输。Netty提供了ChannelHandlerContext对象的writeAndFlush()方法,可以直接将...
标签"java protob"进一步确认了这个压缩包与Java编程语言和Protobuf协议相关。 在解压后的文件中,我们可以预期找到以下内容: 1. `protobuf.jar`:Java库文件,包含了 Protobuf 的Java API,开发者可以在项目中...
标题中的“JAVA接入protobuf”指的是在Java环境中使用Google的Protocol Buffers(简称protobuf)技术进行数据序列化和反序列化的过程。protobuf是一种高效、简洁、跨平台的数据交换格式,它提供了一种方式来定义数据...
在Java环境中,protobuf提供了对应的库,即protobuf-java,使得开发者能够方便地在Java程序中使用protobuf进行数据交换。 标题中的"protobuf序列化JAVA使用的JAR包V3.15"指的是protobuf的Java实现,版本为3.15,以...
在Java环境中,我们可以使用protobuf编译器来生成Java类,这些类可以轻松地进行数据编码和解码。 本教程将指导你如何使用Java直接运行protobuf demo,生成protobuf所需的Java类,并展示如何读取和写入protobuf数据...
标题“C# Java生成protobuf工具pro”指的是专门用于C#和Java环境的protobuf编译工具,可能是一个高级版或者专业版,能够帮助开发者更便捷地处理protobuf相关的编码和解码工作。 描述中的“C#Java生成protobuf工具...
开发者在项目中引入这个库,就可以在Java代码中使用protobuf的序列化和反序列化功能,进行数据的编码和解码。 在实际开发中,使用protobuf有以下几个步骤: 1. **定义数据结构**:在.proto文件中,使用protobuf...
“java”表示这是protobuf针对Java平台的实现,这意味着它可以被Java应用程序直接使用。“3.0”是protobuf的版本号,每个版本可能包含新功能、性能优化或向后兼容性的改变。“tar”表明这个文件是使用tar工具打包的...
与Java默认的序列化机制相比,protobuf有几个显著优点: 1. 性能:protobuf序列化和反序列化速度比Java序列化快很多。 2. 数据大小:protobuf编码的数据通常比JSON或XML更小,节省了存储和网络传输成本。 3. 版本...
1. **高效性**:protobuf生成的二进制编码方式比XML或JSON更节省空间和时间,适合在网络传输和存储中使用。 2. **易用性**:通过定义.proto文件,可以清晰地描述数据结构,编译器会自动生成Java、C++、Python等多...
开发者在Java项目中引入这个jar包,就可以在Java程序中使用protobuf API来编码和解码protobuf消息。 使用步骤: - 定义.proto文件,其中包含protobuf消息类型和字段的定义。 - 使用protoc编译器(即将讨论的工具...
4. **Protobuf与Java的集成**:在Java项目中,引入`protobuf-java-3.5.1.jar`库,可以使得项目能够读写Protobuf格式的数据。而`protobuf-java-util-3.5.1.jar`提供了额外的功能,如将Protobuf消息转换为JSON,这对于...
- **编码规则**:protobuf使用高效的二进制编码方式,比XML或JSON更节省空间。 - **编译器**:protoc是protobuf的核心工具,它可以将.proto文件编译为目标语言的代码,如Java、C++或Python。 - **API使用**:在Java...
标签"protojava"表明这些文件与protobuf在Java平台上的使用有关。 在压缩包中,有两个主要的文件: 1. protoc.exe:如前所述,这是protobuf编译器,用于将.proto文件编译成不同语言的源代码。 2. protobuf-java-...
Java protobuf框架使用向导ProtoBuf,全称是Protocol Buffers, 它是谷歌内部用的一种高效的、可扩展的对结构化数据进行编码的格式规范。谷歌自己内部很多程序之间的通信协议都用了ProtoBuf
在实际使用中,你需要将protobuf-java-2.4.1.jar添加到项目类路径中,这样就可以使用protobuf的API进行数据序列化和反序列化操作。例如: ```java Person person = Person.newBuilder() .setName("张三") .setId...
标题中的"protobuf demo"指的是一个使用Protocol Buffers(简称protobuf)技术的Java示例项目。Protocol Buffers是Google开发的一种数据序列化协议,用于高效地序列化结构化数据,广泛应用于网络通信和数据存储等...
标签"protobuf-java"明确指出了这个压缩包与Java语言版本的Protobuf相关。在Java项目中,使用Protobuf可以提高数据序列化和反序列化的速度,同时减小数据的体积,因为它使用二进制格式,而非JSON或XML等文本格式。 ...
- **编码和解码**:Protobuf使用变长编码技术,使得数据占用的空间与实际值大小有关,节省空间。 通过阅读提供的PDF文档,你将进一步了解Protobuf的Java生成代码细节、编码规则、基础用法以及开发者指南。这些文档...