ちょっとした事情で、assetsに保存したDBファイルを初期データとして使いたいということがありましたが、Android上でどうファイルコピーするのが速いんだろうということで、ネット上の記事を参考に実際にプログラム走らせて調べてみました。
ここで測ったのはAndroid端末内部ストレージ間でのファイルコピー処理です。
結論だけちょろっと言っておくと、1バイトずつコピーとかアホなことさえしなきゃ問題ないというところです。
ソースコードは最後に。
まぁ基本AndroidアプリはJavaだよねということで、Javaでのファイルコピーの速度に関して調べた記事(File Copy in Java – Benchmark)を参考にしました。
10種類の方法で軽いファイル(5KB)や重いファイル(50MB)に対するコピー完了までの速度を計測したもので、ソースもDL可能です。
まぁAndroidでも同様だろうけども、念のため調べるかということで試してみました。
環境は次のもの。
・実機:Panasonic P-02E(Android4.1.2)
・バッファサイズ:4096Byte
・コピー元:apkのassetsファイルに保存したファイル
・コピー先:アプリのデータ領域
・コピーファイル:テキストファイル(5MB)
上記のリンクでは10種類の方法で試していましたが、ここでは5種類の方法で試します。
Copy1.1ByteずつFileInputStreamでコピー
Copy2.1ByteずつBufferedInputStreamでコピー
Copy3.Bufferを使ってFileInputStreamでコピー
Copy4.Bufferを使ってBufferedInputStreamでコピー
Copy5.NIOFileChannelを使ったコピー
で、結果が次になります。
Copy1:319.656 sec
Copy2:7.317 sec
Copy3:0.250 sec
Copy4:0.142 sec
Copy5:0.386 sec
バッファサイズに関しては、4096Byteから大きくしたり小さくしたり変えてみましたが、大して変化なし。
そのため、ほどほどの4096の結果のみ記載してます。
1バイトずつコピーする方法は遅く、実用には耐えられないレベルでした。まぁしょうがないですよね。
また、コピー時間に関してはFileInputStreamの方が遅い傾向にありましたが、ほぼ大差ありません。
あと、冒頭のリンクでも述べられていたのですが、NIOでコピーするのが速いのはある程度ファイルサイズがある時ということで、これはAndroid上でも一緒でした。
冒頭のサイトを読んだ時も思いましたが、意外とFileINputStreamやBufferedInputStreamよりも遅い。
上記サイトの結果を踏まえると、50MBとかの大きいファイルサイズのデータをコピーしたいときは、NIOでコピーしてあげた方がおそらく良いと思います。
今回はassetsからファイルをコピーするという前提があるため、1ファイル当たりのサイズ最大値は5MBです。
とういことで、今回調べたかった環境で一番早くコピーするには
・Copy4.Bufferを使ってBufferedInputStreamでコピー
しとけば良いということでした。
あとは、JNIでコピーしたらどうなるのかなーとかも思っていますが、まだ行ってはいません。
いつか気が向いたらやります。
プログラムや記事に何か間違いがあればコメント頂けると幸いです。
ここで測ったのはAndroid端末内部ストレージ間でのファイルコピー処理です。
結論だけちょろっと言っておくと、1バイトずつコピーとかアホなことさえしなきゃ問題ないというところです。
ソースコードは最後に。
まぁ基本AndroidアプリはJavaだよねということで、Javaでのファイルコピーの速度に関して調べた記事(File Copy in Java – Benchmark)を参考にしました。
10種類の方法で軽いファイル(5KB)や重いファイル(50MB)に対するコピー完了までの速度を計測したもので、ソースもDL可能です。
まぁAndroidでも同様だろうけども、念のため調べるかということで試してみました。
環境は次のもの。
・実機:Panasonic P-02E(Android4.1.2)
・バッファサイズ:4096Byte
・コピー元:apkのassetsファイルに保存したファイル
・コピー先:アプリのデータ領域
・コピーファイル:テキストファイル(5MB)
上記のリンクでは10種類の方法で試していましたが、ここでは5種類の方法で試します。
Copy1.1ByteずつFileInputStreamでコピー
Copy2.1ByteずつBufferedInputStreamでコピー
Copy3.Bufferを使ってFileInputStreamでコピー
Copy4.Bufferを使ってBufferedInputStreamでコピー
Copy5.NIOFileChannelを使ったコピー
で、結果が次になります。
Copy1:319.656 sec
Copy2:7.317 sec
Copy3:0.250 sec
Copy4:0.142 sec
Copy5:0.386 sec
バッファサイズに関しては、4096Byteから大きくしたり小さくしたり変えてみましたが、大して変化なし。
そのため、ほどほどの4096の結果のみ記載してます。
1バイトずつコピーする方法は遅く、実用には耐えられないレベルでした。まぁしょうがないですよね。
また、コピー時間に関してはFileInputStreamの方が遅い傾向にありましたが、ほぼ大差ありません。
あと、冒頭のリンクでも述べられていたのですが、NIOでコピーするのが速いのはある程度ファイルサイズがある時ということで、これはAndroid上でも一緒でした。
冒頭のサイトを読んだ時も思いましたが、意外とFileINputStreamやBufferedInputStreamよりも遅い。
上記サイトの結果を踏まえると、50MBとかの大きいファイルサイズのデータをコピーしたいときは、NIOでコピーしてあげた方がおそらく良いと思います。
今回はassetsからファイルをコピーするという前提があるため、1ファイル当たりのサイズ最大値は5MBです。
とういことで、今回調べたかった環境で一番早くコピーするには
・Copy4.Bufferを使ってBufferedInputStreamでコピー
しとけば良いということでした。
あとは、JNIでコピーしたらどうなるのかなーとかも思っていますが、まだ行ってはいません。
いつか気が向いたらやります。
プログラムや記事に何か間違いがあればコメント頂けると幸いです。
Copy1
Copy2
Copy3
Copy4
Copy5
ソースコードはコチラ
/**
* Copy file using FileInput/OutputStream by byte.
* @param inStream
* @param dst
* @return
* @throws IOException
*/
public static long copyFileUsingFileInputStreamByByte(InputStream inStream, String dst) throws IOException {
Date start = null;
Date end = null;
// copy
OutputStream outStream = null;
try {
start = new Date();
outStream = new FileOutputStream(dst);
int data = -1;
while ((data = inStream.read()) != -1) {
outStream.write(data);
}
end = new Date();
} catch (FileNotFoundException e) {
e.printStackTrace();
throw e;
} catch (IOException e) {
e.printStackTrace();
throw e;
} finally {
close(inStream);
close(outStream);
}
return end.getTime() - start.getTime();
}
Copy2
/**
* Copy file using BufferedInput/OutputStream by byte.
* @param inStream
* @param dst destination file path.
* @return copy time(milli second).
* @throws IOException
*/
public static long copyFileUsingBufferedInputStreamByByte(InputStream inStream, String dst) throws IOException {
Date start = null;
Date end = null;
// copy
OutputStream outStream = null;
try {
start = new Date();
outStream = new BufferedOutputStream(new FileOutputStream(dst));
int data = -1;
while ((data = inStream.read()) != -1) {
outStream.write(data);
}
end = new Date();
} catch (FileNotFoundException e) {
e.printStackTrace();
throw e;
} catch (IOException e) {
e.printStackTrace();
throw e;
} finally {
close(inStream);
close(outStream);
}
return end.getTime() - start.getTime();
}
Copy3
/**
* Copy file using FileInput/OutputStream by buffer.
* @param inStream
* @param dst
* @return
* @throws IOException
*/
public static long copyFileUsingFileInputStreamByBuffer(InputStream inStream, String dst) throws IOException {
Date start = null;
Date end = null;
// copy
OutputStream outStream = null;
try {
start = new Date();
outStream = new FileOutputStream(dst);
int data = -1;
byte[] buf = new byte[BUFFER_SIZE];
while ((data = inStream.read(buf)) != -1) {
outStream.write(buf, 0, data);
}
end = new Date();
} catch (FileNotFoundException e) {
e.printStackTrace();
throw e;
} catch (IOException e) {
e.printStackTrace();
throw e;
} finally {
close(inStream);
close(outStream);
}
return end.getTime() - start.getTime();
}
Copy4
/**
* Copy file using BufferedInput/OutputStream by buffer.
* @param inStream
* @param dst destination file path.
* @return copy time(milli second).
* @throws IOException
*/
public static long copyFileUsingBufferedInputStreamByBuffer(InputStream inStream, String dst) throws IOException {
Date start = null;
Date end = null;
// copy
OutputStream outStream = null;
try {
start = new Date();
outStream = new BufferedOutputStream(new FileOutputStream(dst));
int data = -1;
byte[] buf = new byte[BUFFER_SIZE];
while ((data = inStream.read(buf)) != -1) {
outStream.write(buf, 0, data);
}
end = new Date();
} catch (FileNotFoundException e) {
e.printStackTrace();
throw e;
} catch (IOException e) {
e.printStackTrace();
throw e;
} finally {
close(inStream);
close(outStream);
}
return end.getTime() - start.getTime();
}
Copy5
/**
* Copy file using NIO FileChannel by buffer.
* @param inStream
* @param dst
* @return
* @throws IOException
*/
public static long copyFileUsingNIOFileChannelByBuffer(InputStream inStream, String dst) throws IOException {
Date start = null;
Date end = null;
ReadableByteChannel ch = null;
FileChannel out = null;
FileOutputStream outStream = null;
try {
start = new Date();
ch = Channels.newChannel(inStream);
outStream = new FileOutputStream(dst);
out = outStream.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
while (ch.read(buffer) != -1) {
buffer.flip();
out.write(buffer);
buffer.clear();
}
end = new Date();
} catch (IOException e) {
e.printStackTrace();
throw e;
} finally {
close(inStream);
close(ch);
close(outStream);
close(out);
}
return end.getTime() - start.getTime();
}
ソースコードはコチラ

コメント