`

java编码与protobuf使用

阅读更多

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 有以下编码规则:

 

  1. 如果一个字节,最高位(第 8 位)为 0,表示这是一个 ASCII 字符(00 - 7F)。可见,所有 ASCII 编码已经是 UTF-8 了。
  2. 如果一个字节,以 11 开头,连续的 1 的个数暗示这个字符的字节数,例如:110xxxxx 代表它是双字节 UTF-8 字符的首字节。
  3. 如果一个字节,以 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 涉及到的编码

         对于使用中文来说,有 I/O 的地方就会涉及到编码,而大部分 I/O 引起的乱码都是网络 I/O,因为现在几乎所有的应用程序都涉及到网络操作,而数据经过网络传输都是以字节为单位的,所以所有的数据都必须能够被序列化为字节。在 Java 中数据被序列化必须继承 Serializable接口。 
         这里有一个问题:就是要想办法压缩 Cookie 大小,减少网络传输量,当时有选择不同的压缩算法,发现压缩后字符数是减少了,但是并没有减少字节数。所谓的压缩只是将多个单字节字符通过编码转变成一个多字节字符。减少的是 String.length(),而并没有减少最终的字节数。例如将“ab两个字符通过某种编码转变成一个奇怪的字符,虽然字符数从两个变成一个,但是如果采用 UTF-8 编码这个奇怪的字符最后经过编码可能又会变成三个或更多的字节。同样的道理比如整型数字 1234567 如果当成字符来存储,采用 UTF-8 来编码占用 7 byte,采用 UTF-16 编码将会占用 14 byte,但是把它当成 int型数字来存储只需要 4 byte 来存储。所以看一段文本的大小,看字符本身的长度是没有意义的,即使是一样的字符采用不同的编码最终存储的大小也会不同,所以从字符到字节一定要看编码类型。
5、protobuf介绍及应用
1>使用方法

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>序列化和反序列化分析

1packageoptionjava_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

3message的编码特点

         PB之所以解析速度快、所占体积小,很大程度上是由它序列化的编码特点来决定的。

3.1 Base 128 Varints

        PB采用了Base 128 Varints来变长编码整数:

    变长编码的整数,它可能包含多个byte,对于每个byte8位,其中后7位表示数值,最高的一位表示是否还有还有另一个byte0表示没有,1表示有;

越前面的byte表示数值的低位,越后面的byte表示数值的高位;

 

例子:
300   varints  编码为:1010 1100 0000 0010

解释如下:
3002进制编码为:0001 0010 1100
按照刚才的规则,高低位颠倒,截取最后的7为放在第一个byte,则第一byte1010 1100(其中最高位1表示,后续还有byte);接着剩下的内容放到第二个byte,为0000 0010(其中最高位0表示,后续无byte,这个数到这里截止了)。
于是,合在一起为 1010 1100 0000 0010

PBkey编码成下面的结构: 

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具有跨平台、解析速度快、序列化数据体积小、扩展性高、使用简单的特点。但是我们也可以看到,相比于XMLPB的数据,并不是自然可读的;同时它生成的代码不是纯pojo,对于代码有一定的侵入性。例如pb不支持像Map<Long, 0bject>,其中Object会出现多种不确定的类型,这样就无法通过pb序列化。从上述分析的数据可以看出,protobuf采用的k-v存储结构,并且采用变长的字节编码格式,所以从空间效率比较高

  • 大小: 10.1 KB
  • 大小: 10.6 KB
  • 大小: 60.8 KB
  • 大小: 79.9 KB
  • 大小: 59.5 KB
分享到:
评论

相关推荐

    protobuf java 工程示例

    5. **protobuf与JSON互操作**:protobuf还支持与JSON格式的互换,这在API接口或者需要人类可读格式时非常有用。可以使用`JsonFormat`类进行JSON与protobuf对象之间的转换。 6. **protobuf扩展性**:protobuf支持可...

    ProtoBuf的介绍以及在Java中使用protobuf将对象进行序列化与反序列化示例代码.rar

    4. **使用ProtoBuf与Netty集成** `HelloNetty`可能是一个示例项目,展示如何在使用Netty框架的网络应用中利用ProtoBuf进行数据传输。Netty提供了ChannelHandlerContext对象的writeAndFlush()方法,可以直接将...

    Protobuf3.4 java

    标签"java protob"进一步确认了这个压缩包与Java编程语言和Protobuf协议相关。 在解压后的文件中,我们可以预期找到以下内容: 1. `protobuf.jar`:Java库文件,包含了 Protobuf 的Java API,开发者可以在项目中...

    JAVA 接入protobuf

    标题中的“JAVA接入protobuf”指的是在Java环境中使用Google的Protocol Buffers(简称protobuf)技术进行数据序列化和反序列化的过程。protobuf是一种高效、简洁、跨平台的数据交换格式,它提供了一种方式来定义数据...

    protobuf序列化JAVA使用的JAR包V3.15

    在Java环境中,protobuf提供了对应的库,即protobuf-java,使得开发者能够方便地在Java程序中使用protobuf进行数据交换。 标题中的"protobuf序列化JAVA使用的JAR包V3.15"指的是protobuf的Java实现,版本为3.15,以...

    java生成protobufdemo直接运行

    在Java环境中,我们可以使用protobuf编译器来生成Java类,这些类可以轻松地进行数据编码和解码。 本教程将指导你如何使用Java直接运行protobuf demo,生成protobuf所需的Java类,并展示如何读取和写入protobuf数据...

    C#Java生成protobuf工具pro

    标题“C# Java生成protobuf工具pro”指的是专门用于C#和Java环境的protobuf编译工具,可能是一个高级版或者专业版,能够帮助开发者更便捷地处理protobuf相关的编码和解码工作。 描述中的“C#Java生成protobuf工具...

    protoc.exe和protobuf-java-3.6.1集合

    开发者在项目中引入这个库,就可以在Java代码中使用protobuf的序列化和反序列化功能,进行数据的编码和解码。 在实际开发中,使用protobuf有以下几个步骤: 1. **定义数据结构**:在.proto文件中,使用protobuf...

    protobuf-java-3.0.0.tar.gz

    “java”表示这是protobuf针对Java平台的实现,这意味着它可以被Java应用程序直接使用。“3.0”是protobuf的版本号,每个版本可能包含新功能、性能优化或向后兼容性的改变。“tar”表明这个文件是使用tar工具打包的...

    java序列化之protobuf

    与Java默认的序列化机制相比,protobuf有几个显著优点: 1. 性能:protobuf序列化和反序列化速度比Java序列化快很多。 2. 数据大小:protobuf编码的数据通常比JSON或XML更小,节省了存储和网络传输成本。 3. 版本...

    protobuf-java-3.17.0.zip

    1. **高效性**:protobuf生成的二进制编码方式比XML或JSON更节省空间和时间,适合在网络传输和存储中使用。 2. **易用性**:通过定义.proto文件,可以清晰地描述数据结构,编译器会自动生成Java、C++、Python等多...

    protobuf--java-3.2.0.jar & protoc-3.2.0-windows-x86_32.exe

    开发者在Java项目中引入这个jar包,就可以在Java程序中使用protobuf API来编码和解码protobuf消息。 使用步骤: - 定义.proto文件,其中包含protobuf消息类型和字段的定义。 - 使用protoc编译器(即将讨论的工具...

    protobuf-java-3.5

    4. **Protobuf与Java的集成**:在Java项目中,引入`protobuf-java-3.5.1.jar`库,可以使得项目能够读写Protobuf格式的数据。而`protobuf-java-util-3.5.1.jar`提供了额外的功能,如将Protobuf消息转换为JSON,这对于...

    protobuf-java-3.10.0.zip

    - **编码规则**:protobuf使用高效的二进制编码方式,比XML或JSON更节省空间。 - **编译器**:protoc是protobuf的核心工具,它可以将.proto文件编译为目标语言的代码,如Java、C++或Python。 - **API使用**:在Java...

    protobuf-java-3.3.0.jar、 protobuf.exe

    标签"protojava"表明这些文件与protobuf在Java平台上的使用有关。 在压缩包中,有两个主要的文件: 1. protoc.exe:如前所述,这是protobuf编译器,用于将.proto文件编译成不同语言的源代码。 2. protobuf-java-...

    Java protobuf框架使用向导ProtoBuf

    Java protobuf框架使用向导ProtoBuf,全称是Protocol Buffers, 它是谷歌内部用的一种高效的、可扩展的对结构化数据进行编码的格式规范。谷歌自己内部很多程序之间的通信协议都用了ProtoBuf

    protobuf实例protobuf-java-2.4.1.jar

    在实际使用中,你需要将protobuf-java-2.4.1.jar添加到项目类路径中,这样就可以使用protobuf的API进行数据序列化和反序列化操作。例如: ```java Person person = Person.newBuilder() .setName("张三") .setId...

    protobuf demo

    标题中的"protobuf demo"指的是一个使用Protocol Buffers(简称protobuf)技术的Java示例项目。Protocol Buffers是Google开发的一种数据序列化协议,用于高效地序列化结构化数据,广泛应用于网络通信和数据存储等...

    protobuf-java-3.6.0.zip

    标签"protobuf-java"明确指出了这个压缩包与Java语言版本的Protobuf相关。在Java项目中,使用Protobuf可以提高数据序列化和反序列化的速度,同时减小数据的体积,因为它使用二进制格式,而非JSON或XML等文本格式。 ...

    Google Protobuf 编译 成 java 文件

    - **编码和解码**:Protobuf使用变长编码技术,使得数据占用的空间与实际值大小有关,节省空间。 通过阅读提供的PDF文档,你将进一步了解Protobuf的Java生成代码细节、编码规则、基础用法以及开发者指南。这些文档...

Global site tag (gtag.js) - Google Analytics