java使用缓冲区读取文件

最近发布了 有效的Java第三版 ,我一直对确定此类Java开发书籍的更新感兴趣,该书籍的最新版本仅通过Java 6进行了介绍 。 在此版本中,显然存在与Java 7 , Java 8和Java 9密切相关的全新项目,例如第7章(“ Lambda和流”)中的项目42至48,项目9(“建议尝试使用资源”最终尝试”)和第55条(“明智地退还可选方案”)。 我(非常有点)惊讶地发现, Effective Java第三版中有一个新项目,并不是由Java的新版本专门驱动的,而是由独立于Java版本的软件开发领域的开发驱动的。 第85项(“ Java序列化的首选替代品”)是促使我撰写此介绍性文章的内容,内容涉及将Google的Protocol Buffers与Java结合使用 。

在第三版的有效Java的项目85中,Josh Bloch以粗体强调了以下两个与Java序列化有关的断言:

  1. 避免序列化攻击的最佳方法是永远不要反序列化任何东西。
  2. 您没有理由在您编写的任何新系统中使用Java序列化。

在概述了Java反序列化的危险并做出了这些大胆的声明后,Bloch建议Java开发人员使用他所谓的(跨平台的结构化数据表示形式)(以避免在讨论Java时与术语“序列化”相关的混淆)。 Bloch指出,该类别中的领先产品是JSON ( JavaScript对象表示法 )和协议缓冲区 ( protobuf )。 我发现提到协议缓冲区很有趣,因为最近我一直在阅读和使用协议缓冲区。 在线全面介绍了JSON(甚至Java)的用法。 我觉得Java开发人员对协议缓冲区的了解可能比对JSON的了解要少,因此感觉有必要在Java上使用协议缓冲区。

Google的协议缓冲区在其项目页面上被描述为“一种语言中立,平台中立的可扩展机制,用于序列化结构化数据。” 该页面添加了“思考XML,但是更小,更快,更简单”。 尽管协议缓冲区的优点之一是它们支持以可以被多种编程语言使用的方式表示数据,但本文的重点仅在于将协议缓冲区与Java结合使用。

有一些与协议缓冲区相关的有用在线资源,包括主项目页面 , GitHub protobuf项目页面 , proto3语言指南 (也提供proto2语言指南 ), 协议缓冲区基础:Java教程, Java生成的代码指南 , Java API(Javadoc)文档 ,“ 协议缓冲区”发布页面和“ Maven存储库”页面 。 本文中的示例基于协议缓冲区3.5.1 。

协议缓冲区基础:Java教程概述了将协议缓冲区与Java一起使用的过程。 与使用Java相比,它涵盖了使用Java时要考虑的更多可能性和事情。 第一步是定义独立于语言的协议缓冲区格式。 这是在扩展名为.proto的文本文件中完成的。 在我的示例中,我已经在下一个代码清单中显示的文件album.proto描述了协议格式。

原始专辑

syntax = "proto3";option java_outer_classname = "AlbumProtos";
option java_package = "dustin.examples.protobuf";message Album
{string title = 1;repeated string artist = 2;int32 release_year = 3;repeated string song_title = 4;
}

尽管上面对协议格式的定义很简单,但其中有很多内容。 第一行明确指出我使用的是proto3,而不是未明确指定时使用的默认默认proto2 。 以option开头的两行仅在使用该协议格式生成Java代码时才有意义,它们指示最外层类的名称以及该最外层类的软件包,该类将被生成以供Java应用程序使用此协议格式使用。

“ message”关键字表示此结构(此处称为“相册”)需要表示。 此构造中有四个字段,其中三个是string格式,一个是整数( int32 )。 四个字段中的两个在给定消息中可以不止一次存在,因为它们用repeated保留字注释。 请注意,我创建该定义时没有考虑Java,除了两个option s,它们指定了根据此格式规范生成Java类的详细信息。

所述album.proto上述未示出的文件需要被“编译”到Java源类文件( AlbumProtos.javadustin.examples.protobuf包),将允许写入和读出协议缓冲器的二进制格式的对应于定义的协议格式。 使用适当的基于操作系统的存档文件中包含的protoc编译器可以完成Java源代码文件的生成。 就我而言,因为我正在Windows 10中运行此示例,所以我下载并解压缩了protoc-3.5.1-win32.zip以便访问该protoc工具。 下一个图像使用命令protoc --proto_path=src --java_out=dist\generated album.proto描绘了我对album.proto运行protoc

对于运行上面的,我有我的album.proto在文件src目录中指出--proto_path和我有一个创建(但空)目录下名为build\generated生成的Java源代码被放置在由按规定--java_out标志。

指定包中生成的类的Java源代码文件AlbumProtos.java有1000行以上,我不会在此处列出生成的类源代码,但是可以在GitHub上找到 。 关于生成的代码,需要注意的几件有趣的事情是缺少导入语句(完全合格的包名称代替了所有类引用)。 Java生成的代码指南中提供了有关由protoc生成的Java源代码的更多详细信息。 重要的是要注意,这个生成的类AlbumProtos仍然不受我自己的任何Java应用程序代码的影响,并且仅由文章前面显示的album.proto文本文件生成。

有了可用于AlbumProtos的生成的Java源代码,我现在将在其中生成此类的目录添加到IDE的源路径中,因为现在我将其视为源代码文件。 我也可以将其编译为.class.jar用作库。 现在,在我的源路径中有了这个生成的Java源代码文件,我可以将其与自己的代码一起构建。

在继续本示例之前,我们需要一个简单的Java类来用Protocol Buffers表示。 为此,我将使用下一个代码清单(也在GitHub上提供 )中定义的Album类。

相册.java

package dustin.examples.protobuf;import java.util.ArrayList;
import java.util.List;/*** Music album.*/
public class Album
{private final String title;private final List<String> artists;private final int releaseYear;private final List<String> songsTitles;private Album(final String newTitle, final List<String> newArtists,final int newYear, final List<String> newSongsTitles){title = newTitle;artists = newArtists;releaseYear = newYear;songsTitles = newSongsTitles;}public String getTitle(){return title;}public List<String> getArtists(){return artists;}public int getReleaseYear(){return releaseYear;}public List<String> getSongsTitles(){return songsTitles;}@Overridepublic String toString(){return "'" + title + "' (" + releaseYear + ") by " + artists + " features songs " + songsTitles;}/*** Builder class for instantiating an instance of* enclosing Album class.*/public static class Builder{private String title;private ArrayList<String> artists = new ArrayList<>();private int releaseYear;private ArrayList<String> songsTitles = new ArrayList<>();public Builder(final String newTitle, final int newReleaseYear){title = newTitle;releaseYear = newReleaseYear;}public Builder songTitle(final String newSongTitle){songsTitles.add(newSongTitle);return this;}public Builder songsTitles(final List<String> newSongsTitles){songsTitles.addAll(newSongsTitles);return this;}public Builder artist(final String newArtist){artists.add(newArtist);return this;}public Builder artists(final List<String> newArtists){artists.addAll(newArtists);return this;}public Album build(){return new Album(title, artists, releaseYear, songsTitles);}}
}

在定义了Java“数据”类(“ Album )并使用协议缓冲区生成的Java类(可以表示该专辑)的情况下( AlbumProtos.java ),我准备编写Java应用程序代码以“序列化”专辑信息,而无需使用Java序列化。 此应用程序(演示)代码位于GitHub上可用的AlbumDemo类中, 在本文中 ,我将着重AlbumDemo该类。

我们需要生成一个用于示例的Album实例,并通过下一个硬编码列表来完成。

生成Album样本实例

/*** Generates instance of Album to be used in demonstration.** @return Instance of Album to be used in demonstration.*/
public Album generateAlbum()
{return new Album.Builder("Songs from the Big Chair", 1985).artist("Tears For Fears").songTitle("Shout").songTitle("The Working Hour").songTitle("Everybody Wants to Rule the World").songTitle("Mothers Talk").songTitle("I Believe").songTitle("Broken").songTitle("Head Over Heels").songTitle("Listen").build();
}

协议缓冲区生成的类AlbumProtos类包括一个嵌套的AlbumProtos.Album类,我将使用该类以二进制形式存储我的Album实例的内容。 下一个代码清单演示了如何完成此操作。

Album实例化AlbumProtos.Album

final Album album = instance.generateAlbum();
final AlbumProtos.Album albumMessage= AlbumProtos.Album.newBuilder().setTitle(album.getTitle()).addAllArtist(album.getArtists()).setReleaseYear(album.getReleaseYear()).addAllSongTitle(album.getSongsTitles()).build();

如前面的代码清单所示,“生成器”用于填充协议缓冲区生成的类的不可变实例。 参照该实例,我现在可以使用toByteArray()方法在该实例上以协议缓冲区的二进制形式轻松写出该实例的内容,如下面的代码清单所示。

写作AlbumProtos.Album二进制形式

final byte[] binaryAlbum = albumMessage.toByteArray();

如下面的代码清单所示,可以完成将byte[]数组读回Album实例的操作。

AlbumProtos.Album二进制形式实例化Album

/*** Generates an instance of Album based on the provided* bytes array.** @param binaryAlbum Bytes array that should represent an*    AlbumProtos.Album based on Google Protocol Buffers*    binary format.* @return Instance of Album based on the provided binary form*    of an Album; may be {@code null} if an error is encountered*    while trying to process the provided binary data.*/
public Album instantiateAlbumFromBinary(final byte[] binaryAlbum)
{Album album = null;try{final AlbumProtos.Album copiedAlbumProtos = AlbumProtos.Album.parseFrom(binaryAlbum);final List<String> copiedArtists = copiedAlbumProtos.getArtistList();final List<String> copiedSongsTitles = copiedAlbumProtos.getSongTitleList();album = new Album.Builder(copiedAlbumProtos.getTitle(), copiedAlbumProtos.getReleaseYear()).artists(copiedArtists).songsTitles(copiedSongsTitles).build();}catch (InvalidProtocolBufferException ipbe){out.println("ERROR: Unable to instantiate AlbumProtos.Album instance from provided binary data - "+ ipbe);}return album;
}

如最后一个代码清单所示,在调用生成的类中定义的static方法parseFrom(byte[])过程中,可能引发检查异常InvalidProtocolBufferException 。 获取生成的类的“反序列化”实例本质上是一行,其余几行从生成的类的实例中获取数据,并在原始Album类的实例中设置该数据。

演示类包括两行,这些行打印出原始Album实例的内容,以及最终从二进制表示形式检索到的实例。 这两行包括对两个实例的System.identityHashCode()调用,以证明即使内容匹配,它们也不是同一实例。 当使用前面显示的硬编码的Album实例详细信息执行此代码时,输​​出如下所示:

BEFORE Album (1323165413): 'Songs from the Big Chair' (1985) by [Tears For Fears] features songs [Shout, The Working Hour, Everybody Wants to Rule the World, Mothers Talk, I Believe, Broken, Head Over Heels, Listen]AFTER Album (1880587981): 'Songs from the Big Chair' (1985) by [Tears For Fears] features songs [Shout, The Working Hour, Everybody Wants to Rule the World, Mothers Talk, I Believe, Broken, Head Over Heels, Listen]

从此输出中,我们看到两个实例中的相关字段相同,并且两个实例确实是唯一的。 与使用Java的实现序列化接口的“近乎自动” 序列化机制相比,这需要付出更多的努力,但是与这种方法相关联的重要优势可以证明成本合理。 Josh Bloch在《 Effective Java,第三版》中讨论了Java默认机制中与反序列化相关的安全漏洞,并断言“ 没有理由在您编写的任何新系统中使用Java序列化。

翻译自: https://www.javacodegeeks.com/2018/01/using-googles-protocol-buffers-java.html

java使用缓冲区读取文件

java使用缓冲区读取文件_在Java中使用Google的协议缓冲区相关推荐

  1. 缓冲区溢出_在Java中使用Google的协议缓冲区

    缓冲区溢出 最近发布了有效的Java第三版,我一直对确定此类Java开发书籍的更新感兴趣,该书籍的最新版本仅通过Java 6进行了介绍. 在此版本中,显然存在与Java 7 , Java 8和Java ...

  2. 在Java中使用Google的协议缓冲区

    最近发布了 有效的Java第三版 ,我一直对确定此类Java开发书籍的更新感兴趣,该书籍的最新版本仅通过Java 6进行了介绍 . 在此版本中,显然有与Java 7 , Java 8和Java 9密切 ...

  3. python缓冲区_如何在Python中使用Google的协议缓冲区

    python缓冲区 When people who speak different languages get together and talk, they try to use a languag ...

  4. java 反编译class文件_用Java实现JVM第三章《解析class文件》

    解析class文件 案例介绍 本案例主要介绍通过java代码从class文件中解析:class文件.常量池.属性表: 作为类(或者接口)信息的载体,每个class文件都完整地定义了一个类.为了使jav ...

  5. java 序列化成xml文件_将Java对象序列化成JSON和XML格式

    1.先定义一个Java对象Person: public class Person { String name; int age; int number; public String getName() ...

  6. java缓冲区读取文件_直接从文件读取到BufReader 's or Cursor'的底层缓冲区

    我想弄清楚Rust中的一些基本内容 . 我想创建一个从文件中读取512个字节的工具,并将这些字节复制到另一个文件中 . 然后从输入文件中取出接下来的8个字节并跳过它们 . 然后从输入文件中取下一个51 ...

  7. java在客户端生成文件_用Java编写创建一对客户端/服务器程序,利用数据报将一个文件从一台主机传送到另一...

    展开全部 下面是e5a48de588b63231313335323631343130323136353331333337386564我自己写的一个读取并显示txt文件的demo,希望对您有帮助. pu ...

  8. java错误无法读取配置文件_解决Java Web项目无法读取配置文件问题

    错误描述 报错信息如下图所示,Web应用后台在读取配置文件的时候,系统找不到指定的路径. 这是Java Web项目的目录结构: 这是报错部分的代码: static { try { Properties ...

  9. java itext 导出pdf文件_【Java,PDF】使用Itext实现PDF文件生成

    重要声明:本文章仅仅代表了作者个人对此观点的理解和表述.读者请查阅时持自己的意见进行讨论. 前言 有时候,业务系统要求提供一个PDF文件导出的功能,这时候我们就需要将数据库的对应数据查询出来,然后生成 ...

最新文章

  1. 《从零开始学Swift》学习笔记(Day 7)——Swift 2.0中的print函数几种重载形式
  2. 盘点海外动力电池巨头 细数日韩锂电设备企业
  3. 【直播】如何设计性能更强大的深度卷积神经网络
  4. Java编程中最容易踩雷的地方!
  5. 遍历文件夹还原数据库SQL语句
  6. 指定Gradle构建属性
  7. WPF中制作立体效果的文字或LOGO图形
  8. jsencrypt加密结果false(网罗答案) - 分析篇
  9. linux 每天_每天使用Linux的11种惊人方式
  10. The servlet name already exists.解决方法
  11. chrome jsp 显示不正常_selenium+java谷歌浏览器 网站打开不正常
  12. 销售订单获取不到即时库存
  13. 实现74HC151的8选1数据选择器功能以及用两片74HC151组成一个16选1数据选择器
  14. APM 、PX4, PIXHAWK
  15. android 拼音过滤、匹配首字母
  16. 天线口径与传输速度_如何使用口径将任何电子书传输到Kindle
  17. 人工智能实战2019第七次作业(OpenPAI) 16721088 焦宇恒
  18. 文件监控——watchdog详解
  19. 数字影像系统 接收服务器,RIS/PACS数字医疗影像信息系统的关键技术
  20. Oracle DG 状态健康检查

热门文章

  1. 一些数学小公式/定理的证明
  2. 「LibreOJ Round #11」Misaka Network 与测试 (网络流跑二分图匹配)
  3. YBTOJ:染颜色(KDtree)
  4. 不止代码:机器分配(动态规划)
  5. 二分:[BJWC2008]秦腾与教学评估
  6. P2231-[HNOI2002]跳蚤【容斥】
  7. P3538-[POI2012]OKR-A Horrible Poem【hash,字符串】
  8. POJ2083-Fractal【分形,分治】
  9. jzoj3509-倒霉的小C【gcd,欧拉函数】
  10. 【Manacher】绿绿和串串(luogu 5446)