2013年12月10日火曜日

[Java / Android TIPS] ファイルを分割・結合する

Android というか Java なんですが、ファイルの分割・結合を行うソースを書いてみました。
プロジェクトは Bitbucket で公開してみました。
内容は Windows のサンプル画像を 200KB 毎に分割し、それを結合する。というものです。

src.jpg


ファイル操作には Apache Commons の Commons IO を使っています。ダウンロードは こちら から。
あと、SD カード上でファイル操作を行うのでマニフェストにパーミッション追加をお忘れなく。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />


MainActivity.java
package com.gmail.hyukix.sample_131210_01;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Collection;
import java.util.Locale;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;

import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.widget.Toast;

public class MainActivity extends Activity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // 分割するファイル
    File src = new File(Environment.getExternalStorageDirectory(),
        "Sample/src.jpg");
    if (!src.exists()) {
      String msg = "分割対象ファイルがありません。\n" + src.getAbsolutePath();
      Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
      return;
    }

    // 断片ファイルの拡張子
    String ext = "tmp";

    // 結合先のファイル
    File dst = new File(Environment.getExternalStorageDirectory(),
        "Sample/dst.jpg");

    // ファイル分割 (src.jpg を 200KB 毎に *.tmp へ分割)
    String msg = split(src, ext, 200 * 1024) ? "分割成功!!" : "分割失敗...";
    Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();

    // ファイル結合 (*.tmp を dst.jpg へ結合)
    msg = combine(dst, ext) ? "結合成功!!" : "結合失敗...";
    Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
  }

  /**
   * ファイル分割
   * 
   * @param src 分割ファイル
   * @param ext 断片ファイルの拡張子
   * @param size 断片ファイルの最大ファイルサイズ
   */
  private boolean split(File src, String ext, int size) {
    try {
      // 分割ファイルのストリーム
      FileInputStream in = new FileInputStream(src);

      int cnt = 0;
      while (0 < in.available()) {
        // 断片ファイルを作成
        String dirPath = src.getParent();
        String fileName = String.format(Locale.JAPAN, "%08d.%s", ++cnt, ext);
        File dst = new File(dirPath, fileName);
        FileUtils.touch(dst);

        // 断片ファイルへデータ書き出し
        FileOutputStream out = new FileOutputStream(dst);
        IOUtils.copyLarge(in, out, 0, size);
      }

      return true;

    } catch (Exception ex) {
      ex.printStackTrace();
    }

    return false;
  }

  /**
   * ファイル結合
   * 
   * @param dst 結合ファイル
   * @param ext 断片ファイルの拡張子
   */
  private boolean combine(File dst, String ext) {
    try {
      // 断片ファイルをリスティング
      File dir = dst.getParentFile();
      String[] extensions = { ext };
      boolean recursive = false; // サブディレクトリは対象外
      Collection<File> files = FileUtils.listFiles(dir, extensions, recursive);

      // 断片ファイルを走査
      for (File file : files) {
        // 断片ファイルのデータ
        byte[] data = FileUtils.readFileToByteArray(file);

        // 結合ファイルのストリーム
        boolean append = true; // 追記する
        FileOutputStream out = FileUtils.openOutputStream(dst, append);

        // 断片ファイルを順次結合
        IOUtils.write(data, out);
      }

      return true;

    } catch (Exception ex) {
      ex.printStackTrace();
    }

    return false;
  }
}


/mnt/sdcard/Sample/src.jpg が存在しない場合は左図が表示されます。
存在する場合は分割、結合を行い、右図が表示されます。



エミュレータで実行した様子が下図です。
結合した dst.jpg が元の src.jpg と同じ内容になっていることを確認できました。



こういうのの定石はあるのかしらん。

0 件のコメント:

コメントを投稿