LoginSignup
8
5

More than 5 years have passed since last update.

Android のファイル操作に Okio を使う

Posted at

概要

OkHttp の依存に入っている Okio というライブラリはご存知でしょうか?このライブラリ、OkHttp のおまけで済ますにはもったいないので、ぜひ使ってみましょう。

Okio とは?

アメリカ合衆国の Square, Inc. が開発した I/O ライブラリです。java.iojava.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 アプリのプロジェクトに導入する際の手順を記載します。

依存の追加

OkHttpMoshi をすでに導入している場合は依存でインストールされています。そうでない場合や明示的にバージョンを指定したい場合は、下記の通り build.gradle に追記してください。

app/build.gradle
dependencies {
  implementation 'com.squareup.okio:okio:1.13.0'

ProGuard

公式リポジトリの README に書かれているように、ProGuard を用いる場合は設定の追加が必要です。

app/proguard-rules.pro
-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 を使えば、もう少し冗長さを軽減した書き方ができます。

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 を使って書くことが可能です。

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 を用いる場合は下記の通りです。

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 の処理は割愛します。

Intent 初期化と Storage Access Framework の呼び出し
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "text/html"
intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true)

startActivityForResult(intent, REQUEST_CODE_IMPORT_BOOKMARK)
Storage Access Framework の結果を受け取ってメソッドを呼び出す
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)
    }
}
Uri で指定されたファイルへの書き込みを実行
Okio.buffer(Okio.sink(contentResolver.openOutputStream(uri))).run {
    .writeUtf8(Exporter(bookmarks).invoke())
    .flush()

run を使う場合は以下の通りです。

runを使ってUri で指定されたファイルへの書き込みを実行
Okio.buffer(Okio.sink(contentResolver.openOutputStream(uri))).run {
    writeUtf8(Exporter(bookmarks).invoke())
    flush()
    close()
}

まとめ

Android アプリ開発の際に役立つファイル操作用ライブラリの Okio について説明しました。Android SDK での開発だと煩雑になりそうなファイル入出力を楽に実施できるライブラリです。Kotlin のスコープ関数と組み合わせるとより簡潔な記述も可能になります。HTTP クライアントに OkHttp を使っている場合は依存で入っていますので、せっかくですから使ってみても良いかもしれません。

参考

8
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5