java使用缓冲区读取文件_在Java中使用Google的协议缓冲区
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序列化有關的斷言:
在概述了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.java在dustin.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的协议缓冲区的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓手机在哪里设置输入法切换(安卓手机在
- 下一篇: 代码注释掉还能执行_日志消息是可执行代码