概要
OkHttp の依存に入っている Okio というライブラリはご存知でしょうか?このライブラリ、OkHttp のおまけで済ますにはもったいないので、ぜひ使ってみましょう。
Okio とは?
アメリカ合衆国の Square, Inc. が開発した I/O ライブラリです。java.io
と java.nio
の機能を使いやすくするライブラリとして作られています。Java で実装されています。
背景
Java 6 互換の開発環境では、機能が十分とは言えない File クラスを使う必要があり、
特にファイルを読み書きする処理は、昔の Java の API しか使えない環境ですと割と煩雑になりがちです。自作のファイルユーティリティクラスを作っているプロジェクトもあるかと思います。そうした状況であれば、この Okio を採用して車輪の再発明を回避することが可能です。
Android SDK の依存はないので、Java 6 互換の普通の Java ライブラリとしても使えます。
ですが、通常の Java アプリケーション開発では NIO2 や Apache の Commons IO に含まれる FileUtils がありますので、Java 6 でないといけない環境でない限り、こちらを使うことはないかと思います。
ライセンス
記事を書いている時点では Apache 2.0 で提供されています。アプリで利用する場合はアプリ内にライセンス表記が必要です。
導入
記事を書いている時点での最新は 1.13.0 です。Android アプリのプロジェクトに導入する際の手順を記載します。
依存の追加
OkHttp や Moshi をすでに導入している場合は依存でインストールされています。そうでない場合や明示的にバージョンを指定したい場合は、下記の通り build.gradle に追記してください。
dependencies {
implementation 'com.squareup.okio:okio:1.13.0'
ProGuard
公式リポジトリの README に書かれているように、ProGuard を用いる場合は設定の追加が必要です。
-dontwarn okio.**
使ってみる
Okio には主に buffer/sink/source と、3つの static メソッドが用意されており、buffer に sink か source を組み合わせて使う、と覚えておくと良いと思います。
ファイル読み込み
buffer メソッドと source メソッドを使います。source メソッドの引数には java.io.File, java.io.OutputStream, java.net.Socket, java.nio.file.Path が指定できます。
Okio.buffer(Okio.source(file)).readUtf8()
文字コードは UTF-8 のみ対応しているようです。これは Android が UTF-8 を標準として用いているからだと思われます。
ちゃんとリソースをクローズするときは下記のように書きます。
val bufferedSource: BufferedSource = Okio.buffer(Okio.source(file))
val text: String? = bufferedSource.readUtf8()
bufferedSource.close()
Kotlin の場合はスコープ関数の run を使えば、もう少し冗長さを軽減した書き方ができます。
val text: String? = Okio.buffer(Okio.source(file)).let {
val text = it.readUtf8()
it.close()
return@let text
}
ファイル書き込み
buffer メソッドと sink メソッドを使います。sink メソッドの引数には java.io.File, java.io.OutputStream, java.net.Socket, java.nio.file.Path が指定できます。
sample.json というファイルに出力する場合は下記の通りで書けます。 write メソッドの引数は文字列ではなく、 byte 配列の形式で渡す必要があります。
Kotlin だとこの辺が標準ライブラリの拡張のおかげで多少書きやすくなっています。
Okio.buffer(Okio.sink(File(itemsDir, "sample.json")))
.write(text.toByteArray(charset("UTF-8")))
.flush()
flush() を呼び忘れると実際のファイルへの書き込みが実施されないことに注意してください。
val bufferedSink: BufferedSink = Okio.buffer(Okio.sink(File(itemsDir, "sample.json")))
bufferedSink.write(text.toByteArray(charset("UTF-8")))
bufferedSink.flush()
bufferedSink.close()
これもスコープ関数の run を使って書くことが可能です。
Okio.buffer(Okio.sink(file)).run {
write(contentBytes())
flush()
close()
}
応用
テスト用のリソース読み込み
例えば、テスト用に用いる静的ファイルを app/src/test/resources/html/sample.html
に置いている場合、下記の通りに読み込むことが可能です。
private fun readSource(): String? {
val bufferedSource: BufferedSource = Okio.buffer(Okio.source(classLoader.getResourceAsStream("html/sample.html")))
val sourceText: String? = bufferedSource.readUtf8()
bufferedSource.close()
return sourceText
}
let を用いる場合は下記の通りです。
private fun readSource(): String? =
Okio.buffer(Okio.source(classLoader.getResourceAsStream("html/sample.html"))).let {
val sourceText: String? = it.readUtf8()
it.close()
return sourceText
}
Storage Access Framework で指定したファイルに対して書き込みを実行
RuntimePermission の処理は割愛します。
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "text/html"
intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true)
startActivityForResult(intent, REQUEST_CODE_IMPORT_BOOKMARK)
override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
if (intent == null || resultCode != Activity.RESULT_OK) {
return
}
when (requestCode) {
REQUEST_CODE_EXPORT_BOOKMARK -> writeToContentUri(intent.data)
}
}
Okio.buffer(Okio.sink(contentResolver.openOutputStream(uri))).run {
.writeUtf8(Exporter(bookmarks).invoke())
.flush()
run を使う場合は以下の通りです。
Okio.buffer(Okio.sink(contentResolver.openOutputStream(uri))).run {
writeUtf8(Exporter(bookmarks).invoke())
flush()
close()
}
まとめ
Android アプリ開発の際に役立つファイル操作用ライブラリの Okio について説明しました。Android SDK での開発だと煩雑になりそうなファイル入出力を楽に実施できるライブラリです。Kotlin のスコープ関数と組み合わせるとより簡潔な記述も可能になります。HTTP クライアントに OkHttp を使っている場合は依存で入っていますので、せっかくですから使ってみても良いかもしれません。