Androidアプリで20MBを超える大容量ファイルをアセットに格納する実装手法

大容量ファイルのアセット配置制約と対策

Androidのアセットシステムでは、単一ファイルのサイズ上限が20MBに制限されています。この制約を超えるバイナリデータをアプリに組み込む場合、ファイル分割とランタイムでの再構築が必要です。以下の3ステップで実装します。

  1. 事前処理で大ファイルを分割
  2. 分割ファイルをアセットディレクトリに配置
  3. アプリ実行時にファイルを再結合

分割処理の実装

GNUコマンドラインツールを使用してファイルを20MB単位で分割します。macOSではgsplitコマンドを利用してください。

gsplit --bytes=20M original_data.bin segment_

生成されるファイル名はsegment_aasegment_abのようにアルファベット接尾辞が付与されます。Windows環境ではPowerShellのSplit-Fileコマンドレットを使用可能です。

アセットディレクトリ構成

分割ファイルをapp/src/main/assets/data/ディレクトリに配置します。ファイル名の命名規則は以下の通りです。

  • data/segment_aa
  • data/segment_ab
  • data/segment_ac

ランタイムでのファイル再構築

ActivityまたはViewModel内で、AssetManagerを使用して分割ファイルを順次読み込み、外部ストレージに再結合します。

public void reconstructLargeFile(Context context, File targetFile) {
    try (FileOutputStream outputStream = new FileOutputStream(targetFile)) {
        String[] segments = context.getAssets().list("data");
        if (segments == null) return;
        
        Arrays.sort(segments);
        for (String segment : segments) {
            try (InputStream inputStream = context.getAssets().open("data/" + segment)) {
                byte[] chunkBuffer = new byte[8192];
                int length;
                while ((length = inputStream.read(chunkBuffer)) > 0) {
                    outputStream.write(chunkBuffer, 0, length);
                }
            }
        }
    } catch (IOException e) {
        Log.e("FileReconstruction", "再構築エラー", e);
    }
}

注意点:

  • 分割ファイルの処理順序を保証するため、ファイル名のソートが必要です
  • バッファサイズを8KBに設定し、I/O効率を最適化しています
  • try-with-resources構文でリソースリークを防止しています

実装上の考慮事項

メモリ制約のあるデバイスでは、再結合処理をバックグラウンドスレッドで実行してください。ProgressDialogで処理進捗を表示する実装例は以下の通りです。

new AsyncTask<Void, Integer, Boolean>() {
    protected Boolean doInBackground(Void... params) {
        reconstructLargeFile(context, targetFile);
        return true;
    }
}.execute();

タグ: Android AssetManager ファイル分割 バイナリ処理

6月10日 22:33 投稿