日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java Okio-更加高效易用的IO库

發(fā)布時間:2024/9/30 java 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java Okio-更加高效易用的IO库 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/zhaoyanjun6/article/details/119997762
本文出自【趙彥軍的博客】

Java IO流學(xué)習(xí)總結(jié)一:輸入輸出流
Java IO流學(xué)習(xí)總結(jié)二:File
Java IO流學(xué)習(xí)總結(jié)三:緩沖流-BufferedInputStream、BufferedOutputStream
Java IO流學(xué)習(xí)總結(jié)四:緩沖流-BufferedReader、BufferedWriter
Java IO流學(xué)習(xí)總結(jié)五:轉(zhuǎn)換流-InputStreamReader、OutputStreamWriter
Java IO流學(xué)習(xí)總結(jié)六:ByteArrayInputStream、ByteArrayOutputStream
Java IO流學(xué)習(xí)總結(jié)七:Commons IO 2.5-FileUtils

2021年 Java Okio-更加高效易用的IO庫

文章目錄

  • okio簡介
  • 使用讀取數(shù)據(jù)
    • 練習(xí)1:讀取文本
    • BufferedSource
  • 寫文件 Sink
  • 綜合演練1:文本讀寫
  • 綜合演練2:文件復(fù)制
  • 對象序列化/反序列化
    • 對象序列化/反序列化
    • 序列化數(shù)據(jù)傳輸
    • 序列化數(shù)據(jù)轉(zhuǎn)成base64字符串
  • 數(shù)據(jù)Hash
    • 實戰(zhàn):文本做md5計算
    • 實戰(zhàn):文件做md5計算
  • 數(shù)據(jù)加密 AES
    • AES 簡介
    • OKio 支持的AES加密

okio簡介

Okio是一個庫,它補(bǔ)充了java.io和java.nio,使訪問、存儲和處理數(shù)據(jù)變得更加容易。

OkHttp的的 io 功能就是 OKio 提供的,OkHttp是Android中包含的一個功能強(qiáng)大的HTTP客戶端。

github地址:https://github.com/square/okio

api主頁:https://square.github.io/okio/

maven地址:https://mvnrepository.com/artifact/com.squareup.okio/okio

依賴引入

implementation group: 'com.squareup.okio', name: 'okio', version: '2.10.0'

Okio定義了自己的一套繼承鏈,Source對應(yīng)InputStream, Sink對應(yīng)OutputStream,這樣對比就不難理解了,看一下接口的定義。

public interface Source extends Closeable {long read(Buffer sink, long byteCount) throws IOException;Timeout timeout();@Override void close() throws IOException; }public interface Sink extends Closeable, Flushable {void write(Buffer source, long byteCount) throws IOException;@Override void flush() throws IOException;Timeout timeout();@Override void close() throws IOException; }

使用讀取數(shù)據(jù)

練習(xí)1:讀取文本

/*** 讀取文件中的文本* @param file* @throws IOException*/public void readFile(File file) throws IOException {try (Source fileSource = Okio.source(file)) {Buffer buffer = new Buffer();fileSource.read(buffer, 1024);while (true) {String line = buffer.readUtf8Line();if (line == null) break;System.out.println(line);}}}

可以看到Source 就相當(dāng)于 InputStream , 我們看看 Okio.source(file) 的源碼

/** Returns a source that reads from `file`. */ @Throws(FileNotFoundException::class) fun File.source(): Source = inputStream().source()

再看看 inputStream() 方法

@kotlin.internal.InlineOnly public inline fun File.inputStream(): FileInputStream {return FileInputStream(this) }

是不是很熟悉,還是 Java IO 那一套。只不過是封裝了一層。

我們看看如何創(chuàng)建一個 Source ,它提供了幾個方法

Okio.source(InputStream input) Okio.source(File file) Okio.source(Socket socket)

還有一點,okio 最新版本都用kotlin重新實現(xiàn)了,我們看看,上面的代碼如果用 kotlin 寫是什么樣子的。

/*** 讀取文件中的文本* @param file* @throws IOException*/@Throws(IOException::class)fun readFile(file: File) {file.source().use { fileSource ->val buffer = Buffer()fileSource.read(buffer, 1024)while (true) {val line = buffer.readUtf8Line() ?: breakprintln(line)}}}

是不是簡介了不少。

我們用了一個 Buffer() 類做緩沖類,我們看看它的繼承關(guān)系:

class Buffer : BufferedSource, BufferedSink, Cloneable, ByteChannel {

注意事項:

我們定義了 fileSource.read(buffer, 1024) , 這句話的含義是從文件讀數(shù)據(jù)存入 Buffer 中,最大存入 1024 個字節(jié),返回的是字節(jié)個數(shù),如果文件讀完了,返回 -1 。

所以完整讀取文本文件的代碼為:

public void readFile(File file) throws IOException {try (Source fileSource = Okio.source(file)) {Buffer buffer = new Buffer();while (fileSource.read(buffer, 1024) != -1) {while (true) {//一次讀一行String line = buffer.readUtf8Line();if (line == null) break;System.out.println(line);}}}}

readUtf8Line()一次讀一行,有沒有方法一次把 buffer 里面內(nèi)容讀完,也有的 buffer.readUtf8() , 所以代碼可以改成如下

/*** 讀取文件中的文本** @param file* @throws IOException*/public void readFile(File file) throws IOException {try (Source fileSource = Okio.source(file)) {Buffer buffer = new Buffer();fileSource.read(buffer, 1024);while (fileSource.read(buffer, 1024) != -1) {//一次讀完String line = buffer.readUtf8();System.out.println(line);}}}

BufferedSource

BufferedSource 是一個帶有緩沖功能的 Source , 說白了BufferedSource 其實就是內(nèi)置了一個 Buffer

上面的代碼就可以改成:

/*** 讀取文件中的文本* @param file* @throws IOException*/public void readFile(File file) throws IOException {try (Source fileSource = Okio.source(file)) {BufferedSource bufferedSource = Okio.buffer(fileSource);while (true) {String line = bufferedSource.readUtf8Line();if (line == null) break;System.out.println(line);}}}

readUtf8Line() API讀取所有數(shù)據(jù),直到下一行分隔符\n、\r\n或文件結(jié)尾。它以字符串形式返回該數(shù)據(jù),省略結(jié)尾的分隔符。當(dāng)遇到空行時,該方法將返回一個空字符串。如果沒有更多的數(shù)據(jù)可讀取,它將返回null。

所以我們可以進(jìn)一步優(yōu)化代碼如下:

/*** 讀取文件中的文本** @param file* @throws IOException*/public void readFile(File file) throws IOException {try (Source fileSource = Okio.source(file)) {BufferedSource bufferedSource = Okio.buffer(fileSource);String line;while ((line = bufferedSource.readUtf8Line()) != null) {System.out.println(line);}}}

所以我們也可以優(yōu)化成

/*** 讀取文件中的文本** @param file* @throws IOException*/public void readFile(File file) throws IOException {try (Source fileSource = Okio.source(file); BufferedSource bufferedSource = Okio.buffer(fileSource)) {String line = bufferedSource.readUtf8();System.out.println(line);}}

最后我們可以封裝一個方法來讀取文本文件

/*** 讀取文件中的文本** @param file* @throws IOException*/public String readFile(File file) throws IOException {try (Source fileSource = Okio.source(file); BufferedSource bufferedSource = Okio.buffer(fileSource)) {return bufferedSource.readUtf8();}}

甚至可以更近一步,再簡介一下:

/*** 讀取文件中的文本** @param file* @throws IOException*/public String readFile(File file) throws IOException {try (BufferedSource bufferedSource = Okio.buffer(Okio.source(file))) {return bufferedSource.readUtf8();}}

kotlin 版本如下:

@Throws(IOException::class)fun readFile(file: File): String? {file.source().buffer().use { bufferedSource ->return bufferedSource.readUtf8()}}

是不是很簡潔。

寫文件 Sink

如果文件不存在,會自動創(chuàng)建文件

/*** 把文本寫入文件* @param file* @throws IOException*/public void writeFile(String content, File file) throws IOException {try (Sink sink = Okio.sink(file); BufferedSink bufferedSink = Okio.buffer(sink)) {bufferedSink.write(content.getBytes()); //寫字節(jié)}}

如何創(chuàng)建一個 Sink ?

Okio.sink(File file) Okio.sink(OutputStream outputStream) Okio.sink(Socket sink)

除此之外,還有其他寫數(shù)據(jù)方法:

bufferedSink.write(byte[] bytes) bufferedSink.writeUtf8(String string) bufferedSink.writeAll(Source source) bufferedSink.write(ByteString byteString)

綜合演練1:文本讀寫

我們來實現(xiàn)一個讀文本,然后再寫文本的代碼

public class Test {public static void main(String[] args) {Test test = new Test();try {//從文件讀取文本String string = test.readFile(new File("/Users/xmly/workspace/web1/src/main/aa.txt"));//寫文本到文件test.writeFile(string, new File("/Users/xmly/workspace/web1/src/main/aa1.txt"));} catch (IOException e) {e.printStackTrace();}}/*** 讀取文件中的文本** @param file* @throws IOException*/public String readFile(File file) throws IOException {try (BufferedSource bufferedSource = Okio.buffer(Okio.source(file))) {return bufferedSource.readUtf8();}}/*** 把文本寫入文件** @param file* @throws IOException*/public void writeFile(String content, File file) throws IOException {try (Sink sink = Okio.sink(file); BufferedSink bufferedSink = Okio.buffer(sink)) {bufferedSink.write(content.getBytes());}} }

綜合演練2:文件復(fù)制

public class Test {public static void main(String[] args) {Test test = new Test();try {//從文件讀取文本File file1 = new File("/Users/xmly/Desktop/1234.jpeg");File file2 = new File("/Users/xmly/workspace/web1/src/main/aa1.jpeg");test.copyFile(file1, file2);} catch (IOException e) {e.printStackTrace();}}/*** 復(fù)制文件** @param file1* @param file2* @throws IOException*/public void copyFile(File file1, File file2) throws IOException {try (BufferedSource bufferedSource = Okio.buffer(Okio.source(file1)); BufferedSink bufferedSink = Okio.buffer(Okio.sink(file2))) {bufferedSink.writeAll(bufferedSource);}} }

相比java IO , Okio 簡直是神器,太簡潔,太牛B了

對象序列化/反序列化

序列化:把對象轉(zhuǎn)成二進(jìn)制數(shù)據(jù),可以存儲到本地,也可以網(wǎng)絡(luò)傳輸
反序列化:把二進(jìn)制數(shù)據(jù)轉(zhuǎn)換成對象

通常我們把對象轉(zhuǎn)換成 json 格式的數(shù)據(jù),然后再把 json 轉(zhuǎn)換成對象,這種情況也屬于對象的序列化/對象的反序列化

對象序列化/反序列化

定義 User 對象

public class User implements Serializable {int id;String name; }

定義序列化方法和反序列化方法

/*** 對象序列化 (把對象轉(zhuǎn)成ByteString對象)** @param ob* @return* @throws IOException*/public ByteString serialize(Object ob) throws IOException {Buffer buffer = new Buffer();try (ObjectOutputStream outputStream = new ObjectOutputStream(buffer.outputStream())) {outputStream.writeObject(ob);}return buffer.readByteString();}/*** 對象反序列化 (把ByteString轉(zhuǎn)成對象)** @param byteString* @return*/public Object deserialize(ByteString byteString) throws IOException, ClassNotFoundException {Buffer buffer = new Buffer();buffer.write(byteString);try (ObjectInputStream objectInputStream = new ObjectInputStream(buffer.inputStream())) {return objectInputStream.readObject();}}

我們跑一下,驗證一下結(jié)果:

try {User user = new User();user.id = 100;user.name = "zhaoyanjun";//序列號ByteString byteString = serialize(user);//反序列化User user1 = (User) deserialize(byteString);System.out.println("user = id:" + user1.id + " name:" + user1.name);} catch (IOException | ClassNotFoundException e) {e.printStackTrace(); }

輸出結(jié)果:

user = id:100 name:zhaoyanjun

結(jié)果證明,我們已經(jīng)成功實現(xiàn)了對象的序列化和反序列化。

序列化數(shù)據(jù)傳輸

在上面,我們已經(jīng)把對象序列化了,下面我們把序列化的數(shù)據(jù)保存到本地文件,然后再把本地文件中二進(jìn)制數(shù)據(jù)取出來。其實底層都是操作二進(jìn)制數(shù)據(jù)

/*** 把ByteString寫入文件** @param byteString* @param file* @throws IOException*/public void writeByteStringToFile(ByteString byteString, File file) throws IOException {try (BufferedSink bufferedSink = Okio.buffer(Okio.sink(file))) {bufferedSink.write(byteString);}}/*** 從文件讀數(shù)據(jù)* @param file* @return* @throws IOException*/public ByteString readByteStringFromFile(File file) throws IOException {try (BufferedSource source = Okio.buffer(Okio.source(file))) {return source.readByteString();}}

這就完成了序列化數(shù)據(jù)傳輸。

最后,我們看一下 ByteString 寫入文件后,是什么樣子的?

序列化數(shù)據(jù)轉(zhuǎn)成base64字符串

我們知道序列化后,變成 ByteString ,是個二進(jìn)制數(shù)據(jù),寫入文件或者發(fā)給服務(wù)器還好,如果要想直接發(fā)給同事,就很難了。

其實也有解決的辦法,把二進(jìn)制數(shù)據(jù)轉(zhuǎn)換為 base64 編碼的字符串就可以了。如下:

//把ByteString轉(zhuǎn)為base64編碼的字符串 String base = byteString.base64();//把base64編碼的字符串轉(zhuǎn)成ByteString ByteString newByteString = ByteString.decodeBase64(base);

數(shù)據(jù)Hash

我們這里說的數(shù)據(jù) hash 并不是特指 java 中的 hashCode 方法。而是一種數(shù)據(jù)處理形式,可以理解為 特征處理 , 就是 把任意長度的輸入通過散列算法變換成固定長度的輸出

Hash 的特性:

  • 輸入域無窮,輸出域有限。
  • 輸入?yún)?shù)確定,經(jīng)過hash函數(shù)映射出的返回值一樣。
  • 輸入域上的值經(jīng)過函數(shù)值映射后會幾乎均等的分布在輸出域上
  • 不可逆

常見的 Hash 算法:

  • MD5
  • SHA-1
  • SHA-256
  • SHA-512

ByteString 的 Hash 值的計算

ByteString byteString = readByteString(new File("README.md")); System.out.println(" md5: " + byteString.md5().hex()); System.out.println(" sha1: " + byteString.sha1().hex()); System.out.println("sha256: " + byteString.sha256().hex()); System.out.println("sha512: " + byteString.sha512().hex());

buffers 的 Hash 值的計算

Buffer buffer = readBuffer(new File("README.md")); System.out.println(" md5: " + buffer.md5().hex()); System.out.println(" sha1: " + buffer.sha1().hex()); System.out.println("sha256: " + buffer.sha256().hex()); System.out.println("sha512: " + buffer.sha512().hex());

實戰(zhàn):文本做md5計算

思路:

  • 第一步:把文本轉(zhuǎn)換成 ByteString
  • 第二步:計算 ByteString md5值
/*** 計算字符串md5值** @param data* @return*/public String md5(String data) {ByteString byteString = ByteString.encodeString(data, Charset.forName("UTF-8"));return byteString.md5().hex();}

我們來驗證一下:

System.out.println("md5:" + md5("周五下班了"));

輸出結(jié)果:

md5:e0a0fd4fe31a1ff28b0085e168ca4aef

md5 其他實現(xiàn)方式:http://blog.csdn.net/zhaoyanjun6/article/details/120874209

實戰(zhàn):文件做md5計算

/*** 從文件讀數(shù)據(jù)** @param file* @return* @throws IOException*/public ByteString readByteStringFromFile(File file) throws IOException {try (BufferedSource source = Okio.buffer(Okio.source(file))) {return source.readByteString();}}/*** 計算文件md5值** @param file* @return*/public String md5(File file) {try {return readByteStringFromFile(file).md5().hex();} catch (IOException e) {e.printStackTrace();}return "";}

我做了測試,非常好用,這里就不貼結(jié)果了

md5 其他實現(xiàn)方式:http://blog.csdn.net/zhaoyanjun6/article/details/120874209

數(shù)據(jù)加密 AES

AES 簡介

如果你對AES加密算法不是很了解,請移步到我的另外一篇博客:
AES加密 — 詳解

OKio 支持的AES加密

我們封裝一個方法,來實現(xiàn) aes 加解密。

/*** AES加密** @param bytes* @param file* @param key 秘鑰* @param iv 偏移量* @throws GeneralSecurityException* @throws IOException*/void encryptAes(ByteString bytes, File file, byte[] key, byte[] iv)throws GeneralSecurityException, IOException {Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));try (BufferedSink sink = Okio.buffer(Okio.cipherSink(Okio.sink(file), cipher))) {sink.write(bytes);}}/*** AES解密** @param file* @param key 秘鑰* @param iv 偏移量* @return* @throws GeneralSecurityException* @throws IOException*/ByteString decryptAesToByteString(File file, byte[] key, byte[] iv)throws GeneralSecurityException, IOException {Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));try (BufferedSource source = Okio.buffer(Okio.cipherSource(Okio.source(file), cipher))) {return source.readByteString();}}

我們再來貼一下 Kotlin 的實現(xiàn)

//加密 fun encryptAes(bytes: ByteString, file: File, key: ByteArray, iv: ByteArray) {val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(key, "AES"), IvParameterSpec(iv))val cipherSink = file.sink().cipherSink(cipher)cipherSink.buffer().use { it.write(bytes) } }//解密 fun decryptAesToByteString(file: File, key: ByteArray, iv: ByteArray): ByteString {val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(key, "AES"), IvParameterSpec(iv))val cipherSource = file.source().cipherSource(cipher)return cipherSource.buffer().use { it.readByteString()} }

我們寫一個測試demo跑一下代碼

public class Test {public static void main(String[] args) {Test test = new Test();try {//加密密碼(16位)String key = "zhaoyanjunzhaoy1";//偏移量(16位)String iv = "1234567890123456";//帶加密內(nèi)容ByteString message = ByteString.encodeString("今天是周一,很開心", Charset.forName("UTF-8"));//加密字符串,并且把加密后的內(nèi)容寫入文件File file = new File("/Users/xmly/workspace/web1/src/main/aa2.txt");test.encryptAes(message, file, key.getBytes("utf-8"), iv.getBytes());//解密,把文件內(nèi)容解密出來ByteString sb = test.decryptAesToByteString(file, key.getBytes("utf-8"), iv.getBytes());System.out.println("解密后內(nèi)容:" + sb.string(Charset.forName("UTF-8")));} catch (IOException | GeneralSecurityException e) {e.printStackTrace();}} }

運行結(jié)果如下:

解密后內(nèi)容:今天是周一,很開心

看到,我們已經(jīng)把文件成功解密了

我們再看看,字符串 ”今天是周一,很開心“ 加密后的文件內(nèi)容是什么樣的.


可以看到是亂碼,無法識別,說明加密成功。

總結(jié)

以上是生活随笔為你收集整理的Java Okio-更加高效易用的IO库的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 三年中文免费观看大全动漫 | 欧美一级二级三级视频 | 黄色无遮挡 | 国产青青草视频 | 国产福利小视频在线观看 | av私库在线观看 | 中文在线一区 | 国产福利在线导航 | 中国av一区二区 | 亚洲aaaaaaa| 国精产品一区二区三区 | 美女被草出白浆 | 北条麻妃在线一区 | 国产精品av网站 | 欧美日韩亚洲天堂 | 光明影院手机版在线观看免费 | 熟女毛片| 欧美裸体xxx | 国产精品7777777 | 欧美日韩午夜激情 | 九九爱国产 | 99riav国产精品 | 欧美性猛交xx乱大交 | 欧美xxxx吸乳 | 一级特级片| 亚洲欧美中文日韩在线v日本 | 免费大片在线观看www | 国产精品老牛影视 | 91免费看网站| 伦理黄色片 | 精品国产一区二区三区久久久蜜臀 | 天天综合网天天综合 | 天天看夜夜看 | 精品91久久久久久 | 黄色片免费看 | 黄色三级在线观看 | 欧美性俱乐部 | 亚洲色图2| 久久久久久久久国产 | 激情爱爱网站 | 国产又粗又猛又黄又爽的视频 | 日韩不卡一二三区 | 成人1区 | 亚洲黄在线 | 手机看片一区二区 | 欧美老熟妇xb水多毛多 | 亚洲精品人人 | 中文字幕在线视频第一页 | 91丝袜国产在线观看 | 国产精品高潮呻吟久久av野狼 | 视频在线91 | 女生抠逼视频 | 乱淫67194 | 麻豆av一区二区三区 | 亚洲国产精品久久久久爰性色 | 久久成人黄色 | 日日嗨av一区二区三区四区 | 99热国产在线观看 | 欧美日韩a级| 国产日本视频 | 国产精品丝袜在线 | 欧洲精品码一区二区三区免费看 | 波多野结衣不卡 | 亚洲午夜精品久久久久久app | 人人超碰97 | 中文字幕乱码亚洲无线三区 | 中文字幕av一区二区三区人妻少妇 | 日本免费www | 国产成人精品亚洲男人的天堂 | 色悠悠网 | 97av超碰 | 中国美女一级看片 | 九九热精彩视频 | 抖音视频在线观看 | 欧美日韩中文视频 | 精品欧美乱码久久久久久1区2区 | 香港三日本8a三级少妇三级99 | 夜夜躁很很躁日日躁麻豆 | 日韩欧美毛片 | 日韩高清不卡一区 | 国产精品日韩欧美大师 | 欧美日韩www | 91精品国产综合久久福利软件 | 国产精品免费看 | 亚洲黄色片在线观看 | 午夜福利视频合集1000 | 亚洲妇女体内精汇编 | 成人91在线| 91成人免费在线观看 | 成年视频在线观看 | 性三级视频| 无码人妻精品一区二区三 | 欧美日韩一区二区三区在线视频 | 丰满少妇高潮一区二区 | 肉肉视频在线观看 | 国产精品99久久久久久宅男 | 伊人狼人久久 | 丁香在线视频 | 免费黄色a级片 |