ファイルの読み込み速度をゴニョゴニョしてみた。
今さらですが Java の入出力でファイルの読み込み速度を比較をするプログラムを組んでみた。
Java の入出力の API もバージョンが上がるごとに地味に便利になってきています。
そんなこんなでオーソドックスなスタイルからハイパフォーマンスなものまで適当にやってみました。
とりあえず、ファイルを読み込むだけ(バイト値を合計する処理)のシンプルなものとしました。
既に良く知られていることですが、FileChannel を使えば FileInputStream や BufferedInputStream を使ったオーソドックスなコードより高速に読み込めます。
今回ちょっと気になってたのが下記のものです。
java.nio.file.Files の public static byte[] readAllBytes(Path path) throws IOException です。
非常に興味深い結果を出してくれました。
実は、readAllBytes(Path path) は内部で java.nio.channels パッケージの SeekableByteChannel インタフェースを使っていました。
よって、java.nio.channels を使うのに適している大きめのファイルに対して高速に処理ができるようです。
今まで使ったこと無かったから知らなかった。( ̄▽ ̄;)
しかし、API ドキュメントには「大きなファイルを読み取ることを目的とはしていません。」とあります。
ファイルが 2 ギガバイトを超えるなどした場合、OutOfMemoryError が投げられるようです。
それに「このメソッドは、すべてのバイトが読み取られたか、入出力エラーまたは他の実行時例外がスローされたときに必ずそのファイルがクローズされるようにします。」とあります。
だから大きなファイルには適さないのかもしれません。
本当はこんなにいろいろ比較するつもりじゃなかったのでいつも以上に酷いことになってます。
また、読み込み用ファイルの作成方法も「これは・・・あかんやろ・・・」ってほど非効率なものになっています。(>_<。)
それではプログラムと実行結果を貼っておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 |
package jp.yucchi.filechannelperformancetest; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.nio.channels.SeekableByteChannel; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import static java.nio.file.StandardOpenOption.READ; import java.util.EnumSet; import java.util.logging.Level; import java.util.logging.Logger; /** * * @author Yucchi */ public class FileChannelPerformanceTest { private static File file; private static final boolean DEBUG = false; private static final int REPEAT = 50; private static long start; private static long time; public static void main(String[] args) { System.out.println("テスト用一時ファイル作成開始"); // 効率の悪いファイル作成処理 preparation(); // ウォーミングアップ、処理速度計測処理 for (int i = 0; i < REPEAT; i++) { fileInputStream(); } start = System.nanoTime(); fileInputStream(); time = System.nanoTime() - start; System.out.println(System.lineSeparator() + "(○・ω・)ノ------------- FileInputStream の読み込み時間は、" + (int) (time * 1e-9) / 3_600 + "時間" + (int) ((time * 1e-9) / 60) % 60 + "分" + (int) (time * 1e-9 % 60) + "秒" + Double.toString((time * 1e-9 % 60) % 1).substring(2) + " ------------ )" + System.lineSeparator()); for (int i = 0; i < REPEAT; i++) { bufferedInputStream(); } start = System.nanoTime(); bufferedInputStream(); time = System.nanoTime() - start; System.out.println(System.lineSeparator() + "(○・ω・)ノ------------- BufferedInputStream の読み込み時間は、" + (int) (time * 1e-9) / 3_600 + "時間" + (int) ((time * 1e-9) / 60) % 60 + "分" + (int) (time * 1e-9 % 60) + "秒" + Double.toString((time * 1e-9 % 60) % 1).substring(2) + " ------------ )" + System.lineSeparator()); for (int i = 0; i < REPEAT; i++) { fileChannelOpen(); } start = System.nanoTime(); fileChannelOpen(); time = System.nanoTime() - start; System.out.println(System.lineSeparator() + "(○・ω・)ノ------------- fileChannelOpen の読み込み時間は、" + (int) (time * 1e-9) / 3_600 + "時間" + (int) ((time * 1e-9) / 60) % 60 + "分" + (int) (time * 1e-9 % 60) + "秒" + Double.toString((time * 1e-9 % 60) % 1).substring(2) + " ------------ )" + System.lineSeparator()); for (int i = 0; i < REPEAT; i++) { fileChannelOpenDirectBuffer(); } start = System.nanoTime(); fileChannelOpenDirectBuffer(); time = System.nanoTime() - start; System.out.println(System.lineSeparator() + "(○・ω・)ノ------------- fileChannelOpenDirectBuffer の読み込み時間は、" + (int) (time * 1e-9) / 3_600 + "時間" + (int) ((time * 1e-9) / 60) % 60 + "分" + (int) (time * 1e-9 % 60) + "秒" + Double.toString((time * 1e-9 % 60) % 1).substring(2) + " ------------ )" + System.lineSeparator()); for (int i = 0; i < REPEAT; i++) { fileChannelByteBuffer(); } start = System.nanoTime(); fileChannelByteBuffer(); time = System.nanoTime() - start; System.out.println(System.lineSeparator() + "(○・ω・)ノ------------- fileChannelByteBuffer の読み込み時間は、" + (int) (time * 1e-9) / 3_600 + "時間" + (int) ((time * 1e-9) / 60) % 60 + "分" + (int) (time * 1e-9 % 60) + "秒" + Double.toString((time * 1e-9 % 60) % 1).substring(2) + " ------------ )" + System.lineSeparator()); for (int i = 0; i < REPEAT; i++) { fileChannelDirectByteBuffer(); } start = System.nanoTime(); fileChannelDirectByteBuffer(); time = System.nanoTime() - start; System.out.println(System.lineSeparator() + "(○・ω・)ノ------------- FileChannelDirectByteBuffer の読み込み時間は、" + (int) (time * 1e-9) / 3_600 + "時間" + (int) ((time * 1e-9) / 60) % 60 + "分" + (int) (time * 1e-9 % 60) + "秒" + Double.toString((time * 1e-9 % 60) % 1).substring(2) + " ------------ )" + System.lineSeparator()); for (int i = 0; i < REPEAT; i++) { fileChannelMappedByteBuffer(); } start = System.nanoTime(); fileChannelMappedByteBuffer(); time = System.nanoTime() - start; System.out.println(System.lineSeparator() + "(○・ω・)ノ------------- FileChannelMappedByteBuffer の読み込み時間は、" + (int) (time * 1e-9) / 3_600 + "時間" + (int) ((time * 1e-9) / 60) % 60 + "分" + (int) (time * 1e-9 % 60) + "秒" + Double.toString((time * 1e-9 % 60) % 1).substring(2) + " ------------ )" + System.lineSeparator()); for (int i = 0; i < REPEAT; i++) { fileChannelOpenMappedByteBuffer(); } start = System.nanoTime(); fileChannelOpenMappedByteBuffer(); time = System.nanoTime() - start; System.out.println(System.lineSeparator() + "(○・ω・)ノ------------- FileChannelOpenMappedByteBuffer の読み込み時間は、" + (int) (time * 1e-9) / 3_600 + "時間" + (int) ((time * 1e-9) / 60) % 60 + "分" + (int) (time * 1e-9 % 60) + "秒" + Double.toString((time * 1e-9 % 60) % 1).substring(2) + " ------------ )" + System.lineSeparator()); for (int i = 0; i < REPEAT; i++) { seekableByteChannel(); } start = System.nanoTime(); seekableByteChannel(); time = System.nanoTime() - start; System.out.println(System.lineSeparator() + "(○・ω・)ノ------------- SeekableByteChannel の読み込み時間は、" + (int) (time * 1e-9) / 3_600 + "時間" + (int) ((time * 1e-9) / 60) % 60 + "分" + (int) (time * 1e-9 % 60) + "秒" + Double.toString((time * 1e-9 % 60) % 1).substring(2) + " ------------ )" + System.lineSeparator()); for (int i = 0; i < REPEAT; i++) { seekableByteChannelDirectBuffer(); } start = System.nanoTime(); seekableByteChannelDirectBuffer(); time = System.nanoTime() - start; System.out.println(System.lineSeparator() + "(○・ω・)ノ------------- SeekableByteChannelDirectBuffer の読み込み時間は、" + (int) (time * 1e-9) / 3_600 + "時間" + (int) ((time * 1e-9) / 60) % 60 + "分" + (int) (time * 1e-9 % 60) + "秒" + Double.toString((time * 1e-9 % 60) % 1).substring(2) + " ------------ )" + System.lineSeparator()); for (int i = 0; i < REPEAT; i++) { filesReadAllBytes(); } start = System.nanoTime(); filesReadAllBytes(); time = System.nanoTime() - start; System.out.println(System.lineSeparator() + "(○・ω・)ノ------------- FilesReadAllBytes の読み込み時間は、" + (int) (time * 1e-9) / 3_600 + "時間" + (int) ((time * 1e-9) / 60) % 60 + "分" + (int) (time * 1e-9 % 60) + "秒" + Double.toString((time * 1e-9 % 60) % 1).substring(2) + " ------------ )" + System.lineSeparator()); // お掃除 file.deleteOnExit(); System.out.println("テスト終了!"); } private static void preparation() { try { file = File.createTempFile("temp", ".txt"); } catch (IOException ex) { Logger.getLogger(FileChannelPerformanceTest.class.getName()).log(Level.SEVERE, null, ex); } System.out.println("テスト用一時ファイルを " + Paths.get(file.getAbsolutePath()) + " に作成します。"); String content = "JAVA + YOU, DOWNLOAD TODAY! JAVA + YOU, DOWNLOAD TODAY! JAVA + YOU, DOWNLOAD TODAY!" + System.lineSeparator(); try (FileChannel fileChannel = new FileOutputStream(file.getAbsolutePath()).getChannel(); FileLock lock = fileChannel.lock(0, Long.MAX_VALUE, false)) { long currentPosition = 0L; byte[] bytes = content.getBytes(); while (file.length() < 512 * 1_024 * 1024) { ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); currentPosition += fileChannel.write(byteBuffer, currentPosition); } } catch (IOException ex) { Logger.getLogger(FileChannelPerformanceTest.class.getName()).log(Level.SEVERE, null, ex); } System.out.println("テスト用一時ファイルのサイズは、" + file.length() + " バイトです。" + System.lineSeparator()); } private static void fileInputStream() { try (FileInputStream fis = new FileInputStream(file.getAbsolutePath())) { final int SIZE = 8 * 1_024; byte[] byteArray = new byte[SIZE]; int readPosition; long sum = 0L; while ((readPosition = fis.read(byteArray, 0, SIZE)) != -1) { for (int i = 0; i < readPosition; i++) { sum += byteArray[i]; } } if (DEBUG) { System.out.println("バイト配列の要素の値の合計は、" + sum + " です。" + System.lineSeparator()); } } catch (IOException ex) { Logger.getLogger(FileChannelPerformanceTest.class.getName()).log(Level.SEVERE, null, ex); } } private static void bufferedInputStream() { try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file.getAbsolutePath()))) { final int SIZE = 8 * 1_024; byte[] byteArray = new byte[SIZE]; int readPosition; long sum = 0L; while ((readPosition = bis.read(byteArray, 0, SIZE)) != -1) { for (int i = 0; i < readPosition; i++) { sum += byteArray[i]; } } if (DEBUG) { System.out.println("バイト配列の要素の値の合計は、" + sum + " です。" + System.lineSeparator()); } } catch (IOException ex) { Logger.getLogger(FileChannelPerformanceTest.class.getName()).log(Level.SEVERE, null, ex); } } private static void fileChannelOpen() { try (FileChannel fileChannel = FileChannel.open(Paths.get(file.getAbsolutePath()), StandardOpenOption.READ); FileLock lock = fileChannel.lock(0, Long.MAX_VALUE, true)) { final int CAPACITY = 1_000 * 1_024; ByteBuffer byteBuffer = ByteBuffer.allocate(CAPACITY); int readPosition; long sum = 0L; while ((readPosition = fileChannel.read(byteBuffer)) != -1) { if (readPosition == 0) { continue; } byteBuffer.flip(); while (byteBuffer.hasRemaining()) { sum += byteBuffer.get(); } byteBuffer.clear(); } if (DEBUG) { System.out.println("バイト配列の要素の値の合計は、" + sum + " です。" + System.lineSeparator()); } } catch (IOException ex) { Logger.getLogger(FileChannelPerformanceTest.class.getName()).log(Level.SEVERE, null, ex); } } private static void fileChannelOpenDirectBuffer() { try (FileChannel fileChannel = FileChannel.open(Paths.get(file.getAbsolutePath()), StandardOpenOption.READ); FileLock lock = fileChannel.lock(0, Long.MAX_VALUE, true)) { final int CAPACITY = 1_000 * 1_024; ByteBuffer byteBuffer = ByteBuffer.allocateDirect(CAPACITY); int readPosition; long sum = 0L; while ((readPosition = fileChannel.read(byteBuffer)) != -1) { if (readPosition == 0) { continue; } byteBuffer.flip(); while (byteBuffer.hasRemaining()) { sum += byteBuffer.get(); } byteBuffer.clear(); } if (DEBUG) { System.out.println("バイト配列の要素の値の合計は、" + sum + " です。" + System.lineSeparator()); } } catch (IOException ex) { Logger.getLogger(FileChannelPerformanceTest.class.getName()).log(Level.SEVERE, null, ex); } } private static void fileChannelByteBuffer() { try (FileChannel fileChannel = new FileInputStream(file.getAbsolutePath()).getChannel(); FileLock lock = fileChannel.lock(0, Long.MAX_VALUE, true)) { final int CAPACITY = 1_000 * 1_024; ByteBuffer byteBuffer = ByteBuffer.allocate(CAPACITY); int readPosition; long sum = 0L; while ((readPosition = fileChannel.read(byteBuffer)) != -1) { if (readPosition == 0) { continue; } byteBuffer.flip(); while (byteBuffer.hasRemaining()) { sum += byteBuffer.get(); } byteBuffer.clear(); } if (DEBUG) { System.out.println("バイト配列の要素の値の合計は、" + sum + " です。" + System.lineSeparator()); } } catch (IOException ex) { Logger.getLogger(FileChannelPerformanceTest.class.getName()).log(Level.SEVERE, null, ex); } } private static void fileChannelDirectByteBuffer() { try (FileChannel fileChannel = new FileInputStream(file.getAbsolutePath()).getChannel(); FileLock lock = fileChannel.lock(0, Long.MAX_VALUE, true)) { final int CAPACITY = 1_000 * 1_024; ByteBuffer byteBuffer = ByteBuffer.allocateDirect(CAPACITY); int readPosition; long sum = 0L; while ((readPosition = fileChannel.read(byteBuffer)) != -1) { if (readPosition == 0) { continue; } byteBuffer.flip(); while (byteBuffer.hasRemaining()) { sum += byteBuffer.get(); } byteBuffer.clear(); } if (DEBUG) { System.out.println("バイト配列の要素の値の合計は、" + sum + " です。" + System.lineSeparator()); } } catch (IOException ex) { Logger.getLogger(FileChannelPerformanceTest.class.getName()).log(Level.SEVERE, null, ex); } } private static void fileChannelMappedByteBuffer() { try (FileChannel fileChannel = new FileInputStream(file.getAbsolutePath()).getChannel(); FileLock lock = fileChannel.lock(0, Long.MAX_VALUE, true)) { MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size()); long sum = 0L; while (mappedByteBuffer.hasRemaining()) { sum += mappedByteBuffer.get(); } if (DEBUG) { System.out.println("バイト配列の要素の値の合計は、" + sum + " です。" + System.lineSeparator()); } } catch (IOException ex) { Logger.getLogger(FileChannelPerformanceTest.class.getName()).log(Level.SEVERE, null, ex); } } private static void fileChannelOpenMappedByteBuffer() { try (FileChannel fileChannel = FileChannel.open(Paths.get(file.getAbsolutePath()), StandardOpenOption.READ); FileLock lock = fileChannel.lock(0, Long.MAX_VALUE, true)) { MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size()); long sum = 0L; while (mappedByteBuffer.hasRemaining()) { sum += mappedByteBuffer.get(); } if (DEBUG) { System.out.println("バイト配列の要素の値の合計は、" + sum + " です。" + System.lineSeparator()); } } catch (IOException ex) { Logger.getLogger(FileChannelPerformanceTest.class.getName()).log(Level.SEVERE, null, ex); } } private static void seekableByteChannel() { // FileChannel にあえてキャストしないでみた。 try (SeekableByteChannel seekableByteChannel = Files.newByteChannel(Paths.get(file.getAbsolutePath()), EnumSet.of(READ))) { final int CAPACITY = 1_000 * 1_024; ByteBuffer byteBuffer = ByteBuffer.allocate(CAPACITY); int readPosition; long sum = 0L; while ((readPosition = seekableByteChannel.read(byteBuffer)) != -1) { if (readPosition == 0) { continue; } byteBuffer.flip(); while (byteBuffer.hasRemaining()) { sum += byteBuffer.get(); } byteBuffer.clear(); } if (DEBUG) { System.out.println("バイト配列の要素の値の合計は、" + sum + " です。" + System.lineSeparator()); } } catch (IOException ex) { Logger.getLogger(FileChannelPerformanceTest.class.getName()).log(Level.SEVERE, null, ex); } } private static void seekableByteChannelDirectBuffer() { // FileChannel にあえてキャストしないでみた。 try (SeekableByteChannel seekableByteChannel = Files.newByteChannel(Paths.get(file.getAbsolutePath()), EnumSet.of(READ))) { final int CAPACITY = 1_000 * 1_024; ByteBuffer byteBuffer = ByteBuffer.allocateDirect(CAPACITY); int readPosition; long sum = 0L; while ((readPosition = seekableByteChannel.read(byteBuffer)) != -1) { if (readPosition == 0) { continue; } byteBuffer.flip(); while (byteBuffer.hasRemaining()) { sum += byteBuffer.get(); } byteBuffer.clear(); } if (DEBUG) { System.out.println("バイト配列の要素の値の合計は、" + sum + " です。" + System.lineSeparator()); } } catch (IOException ex) { Logger.getLogger(FileChannelPerformanceTest.class.getName()).log(Level.SEVERE, null, ex); } } private static void filesReadAllBytes() { long sum = 0L; byte[] byteArray = null; try { byteArray = Files.readAllBytes(Paths.get(file.getAbsolutePath())); } catch (IOException ex) { Logger.getLogger(FileChannelPerformanceTest.class.getName()).log(Level.SEVERE, null, ex); } for (int i = 0; i < byteArray.length; i++) { sum += byteArray[i]; } if (DEBUG) { System.out.println("バイト配列の要素の値の合計は、" + sum + " です。" + System.lineSeparator()); } } } |
約2メガバイト
テスト用一時ファイル作成開始
テスト用一時ファイルを C:\Users\Yucchi\AppData\Local\Temp\temp5030517990935223178.txt に作成します。
テスト用一時ファイルのサイズは、2097222 バイトです。
(○・ω・)ノ————- FileInputStream の読み込み時間は、0時間0分0秒0018270110000000001 ———— )
(○・ω・)ノ————- BufferedInputStream の読み込み時間は、0時間0分0秒0016099900000000002 ———— )
(○・ω・)ノ————- fileChannelOpen の読み込み時間は、0時間0分0秒001935356 ———— )
(○・ω・)ノ————- fileChannelOpenDirectBuffer の読み込み時間は、0時間0分0秒001790015 ———— )
(○・ω・)ノ————- fileChannelByteBuffer の読み込み時間は、0時間0分0秒001790015 ———— )
(○・ω・)ノ————- FileChannelDirectByteBuffer の読み込み時間は、0時間0分0秒001814459 ———— )
(○・ω・)ノ————- FileChannelMappedByteBuffer の読み込み時間は、0時間0分0秒001435249 ———— )
(○・ω・)ノ————- FileChannelOpenMappedByteBuffer の読み込み時間は、0時間0分0秒00122087 ———— )
(○・ω・)ノ————- SeekableByteChannel の読み込み時間は、0時間0分0秒0017662320000000002 ———— )
(○・ω・)ノ————- SeekableByteChannelDirectBuffer の読み込み時間は、0時間0分0秒0018725950000000001 ———— )
(○・ω・)ノ————- FilesReadAllBytes の読み込み時間は、0時間0分0秒0010583510000000001 ———— )
テスト終了!
約8メガバイト
テスト用一時ファイル作成開始
テスト用一時ファイルを C:\Users\Yucchi\AppData\Local\Temp\temp8676206647067718269.txt に作成します。
テスト用一時ファイルのサイズは、8388627 バイトです。
(○・ω・)ノ————- FileInputStream の読み込み時間は、0時間0分0秒00741639 ———— )
(○・ω・)ノ————- BufferedInputStream の読み込み時間は、0時間0分0秒007126697 ———— )
(○・ω・)ノ————- fileChannelOpen の読み込み時間は、0時間0分0秒0057324080000000005 ———— )
(○・ω・)ノ————- fileChannelOpenDirectBuffer の読み込み時間は、0時間0分0秒005674932000000001 ———— )
(○・ω・)ノ————- fileChannelByteBuffer の読み込み時間は、0時間0分0秒005462535 ———— )
(○・ω・)ノ————- FileChannelDirectByteBuffer の読み込み時間は、0時間0分0秒005980479 ———— )
(○・ω・)ノ————- FileChannelMappedByteBuffer の読み込み時間は、0時間0分0秒005093565 ———— )
(○・ω・)ノ————- FileChannelOpenMappedByteBuffer の読み込み時間は、0時間0分0秒004786035 ———— )
(○・ω・)ノ————- SeekableByteChannel の読み込み時間は、0時間0分0秒006010209000000001 ———— )
(○・ω・)ノ————- SeekableByteChannelDirectBuffer の読み込み時間は、0時間0分0秒005818622000000001 ———— )
(○・ω・)ノ————- FilesReadAllBytes の読み込み時間は、0時間0分0秒004599734 ———— )
テスト終了!
約16メガバイト
テスト用一時ファイル作成開始
テスト用一時ファイルを C:\Users\Yucchi\AppData\Local\Temp\temp4534373118077736467.txt に作成します。
テスト用一時ファイルのサイズは、16777254 バイトです。
(○・ω・)ノ————- FileInputStream の読み込み時間は、0時間0分0秒014226638000000002 ———— )
(○・ω・)ノ————- BufferedInputStream の読み込み時間は、0時間0分0秒014306246000000002 ———— )
(○・ω・)ノ————- fileChannelOpen の読み込み時間は、0時間0分0秒010903929000000001 ———— )
(○・ω・)ノ————- fileChannelOpenDirectBuffer の読み込み時間は、0時間0分0秒010355595 ———— )
(○・ω・)ノ————- fileChannelByteBuffer の読み込み時間は、0時間0分0秒011318484 ———— )
(○・ω・)ノ————- FileChannelDirectByteBuffer の読み込み時間は、0時間0分0秒010636368 ———— )
(○・ω・)ノ————- FileChannelMappedByteBuffer の読み込み時間は、0時間0分0秒009792727000000001 ———— )
(○・ω・)ノ————- FileChannelOpenMappedByteBuffer の読み込み時間は、0時間0分0秒009329945000000001 ———— )
(○・ω・)ノ————- SeekableByteChannel の読み込み時間は、0時間0分0秒01143806 ———— )
(○・ω・)ノ————- SeekableByteChannelDirectBuffer の読み込み時間は、0時間0分0秒011517998000000002 ———— )
(○・ω・)ノ————- FilesReadAllBytes の読み込み時間は、0時間0分0秒010098274 ———— )
テスト終了!
約32メガバイト
テスト用一時ファイル作成開始
テスト用一時ファイルを C:\Users\Yucchi\AppData\Local\Temp\temp551612105990559011.txt に作成します。
テスト用一時ファイルのサイズは、33554508 バイトです。
(○・ω・)ノ————- FileInputStream の読み込み時間は、0時間0分0秒030031225 ———— )
(○・ω・)ノ————- BufferedInputStream の読み込み時間は、0時間0分0秒030403168 ———— )
(○・ω・)ノ————- fileChannelOpen の読み込み時間は、0時間0分0秒022357514000000002 ———— )
(○・ω・)ノ————- fileChannelOpenDirectBuffer の読み込み時間は、0時間0分0秒022399466 ———— )
(○・ω・)ノ————- fileChannelByteBuffer の読み込み時間は、0時間0分0秒021978635 ———— )
(○・ω・)ノ————- FileChannelDirectByteBuffer の読み込み時間は、0時間0分0秒023581027 ———— )
(○・ω・)ノ————- FileChannelMappedByteBuffer の読み込み時間は、0時間0分0秒020720769 ———— )
(○・ω・)ノ————- FileChannelOpenMappedByteBuffer の読み込み時間は、0時間0分0秒019682567 ———— )
(○・ω・)ノ————- SeekableByteChannel の読み込み時間は、0時間0分0秒021659545000000002 ———— )
(○・ω・)ノ————- SeekableByteChannelDirectBuffer の読み込み時間は、0時間0分0秒023247402 ———— )
(○・ω・)ノ————- FilesReadAllBytes の読み込み時間は、0時間0分0秒024589501000000003 ———— )
テスト終了!
約64メガバイト
テスト用一時ファイル作成開始
テスト用一時ファイルを C:\Users\Yucchi\AppData\Local\Temp\temp2044166890552158221.txt に作成します。
テスト用一時ファイルのサイズは、67108929 バイトです。
(○・ω・)ノ————- FileInputStream の読み込み時間は、0時間0分0秒057892566000000006 ———— )
(○・ω・)ノ————- BufferedInputStream の読み込み時間は、0時間0分0秒058601767000000006 ———— )
(○・ω・)ノ————- fileChannelOpen の読み込み時間は、0時間0分0秒043844631 ———— )
(○・ω・)ノ————- fileChannelOpenDirectBuffer の読み込み時間は、0時間0分0秒042067168 ———— )
(○・ω・)ノ————- fileChannelByteBuffer の読み込み時間は、0時間0分0秒041638081 ———— )
(○・ω・)ノ————- FileChannelDirectByteBuffer の読み込み時間は、0時間0分0秒046523542 ———— )
(○・ω・)ノ————- FileChannelMappedByteBuffer の読み込み時間は、0時間0分0秒040943413000000005 ———— )
(○・ω・)ノ————- FileChannelOpenMappedByteBuffer の読み込み時間は、0時間0分0秒038577977 ———— )
(○・ω・)ノ————- SeekableByteChannel の読み込み時間は、0時間0分0秒042847058 ———— )
(○・ω・)ノ————- SeekableByteChannelDirectBuffer の読み込み時間は、0時間0分0秒045195318000000005 ———— )
(○・ω・)ノ————- FilesReadAllBytes の読み込み時間は、0時間0分0秒039039437 ———— )
テスト終了!
約128メガバイト
テスト用一時ファイル作成開始
テスト用一時ファイルを C:\Users\Yucchi\AppData\Local\Temp\temp7188302575166935320.txt に作成します。
テスト用一時ファイルのサイズは、134217771 バイトです。
(○・ω・)ノ————- FileInputStream の読み込み時間は、0時間0分0秒11521400400000001 ———— )
(○・ω・)ノ————- BufferedInputStream の読み込み時間は、0時間0分0秒11788168500000001 ———— )
(○・ω・)ノ————- fileChannelOpen の読み込み時間は、0時間0分0秒08361375 ———— )
(○・ω・)ノ————- fileChannelOpenDirectBuffer の読み込み時間は、0時間0分0秒08419346400000001 ———— )
(○・ω・)ノ————- fileChannelByteBuffer の読み込み時間は、0時間0分0秒082537891 ———— )
(○・ω・)ノ————- FileChannelDirectByteBuffer の読み込み時間は、0時間0分0秒090252891 ———— )
(○・ω・)ノ————- FileChannelMappedByteBuffer の読み込み時間は、0時間0分0秒080295004 ———— )
(○・ω・)ノ————- FileChannelOpenMappedByteBuffer の読み込み時間は、0時間0分0秒075165433 ———— )
(○・ω・)ノ————- SeekableByteChannel の読み込み時間は、0時間0分0秒086926218 ———— )
(○・ω・)ノ————- SeekableByteChannelDirectBuffer の読み込み時間は、0時間0分0秒090565376 ———— )
(○・ω・)ノ————- FilesReadAllBytes の読み込み時間は、0時間0分0秒10305452100000001 ———— )
テスト終了!
約256メガバイト
テスト用一時ファイル作成開始
テスト用一時ファイルを C:\Users\Yucchi\AppData\Local\Temp\temp2576486197093097661.txt に作成します。
テスト用一時ファイルのサイズは、268435542 バイトです。
(○・ω・)ノ————- FileInputStream の読み込み時間は、0時間0分0秒222832253 ———— )
(○・ω・)ノ————- BufferedInputStream の読み込み時間は、0時間0分0秒22093158100000002 ———— )
(○・ω・)ノ————- fileChannelOpen の読み込み時間は、0時間0分0秒15506372000000002 ———— )
(○・ω・)ノ————- fileChannelOpenDirectBuffer の読み込み時間は、0時間0分0秒15883765 ———— )
(○・ω・)ノ————- fileChannelByteBuffer の読み込み時間は、0時間0分0秒15490747900000001 ———— )
(○・ω・)ノ————- FileChannelDirectByteBuffer の読み込み時間は、0時間0分0秒16721791900000002 ———— )
(○・ω・)ノ————- FileChannelMappedByteBuffer の読み込み時間は、0時間0分0秒16354870200000002 ———— )
(○・ω・)ノ————- FileChannelOpenMappedByteBuffer の読み込み時間は、0時間0分0秒147236411 ———— )
(○・ω・)ノ————- SeekableByteChannel の読み込み時間は、0時間0分0秒166499799 ———— )
(○・ω・)ノ————- SeekableByteChannelDirectBuffer の読み込み時間は、0時間0分0秒17514531700000002 ———— )
(○・ω・)ノ————- FilesReadAllBytes の読み込み時間は、0時間0分0秒19809278700000002 ———— )
テスト終了!
約512メガバイト
テスト用一時ファイル作成開始
テスト用一時ファイルを C:\Users\Yucchi\AppData\Local\Temp\temp8990442498363311781.txt に作成します。
テスト用一時ファイルのサイズは、536870997 バイトです。
(○・ω・)ノ————- FileInputStream の読み込み時間は、0時間0分0秒48024426600000003 ———— )
(○・ω・)ノ————- BufferedInputStream の読み込み時間は、0時間0分0秒46190115600000003 ———— )
(○・ω・)ノ————- fileChannelOpen の読み込み時間は、0時間0分0秒322018374 ———— )
(○・ω・)ノ————- fileChannelOpenDirectBuffer の読み込み時間は、0時間0分0秒347179662 ———— )
(○・ω・)ノ————- fileChannelByteBuffer の読み込み時間は、0時間0分0秒338599217 ———— )
(○・ω・)ノ————- FileChannelDirectByteBuffer の読み込み時間は、0時間0分0秒361760405 ———— )
(○・ω・)ノ————- FileChannelMappedByteBuffer の読み込み時間は、0時間0分0秒330729955 ———— )
(○・ω・)ノ————- FileChannelOpenMappedByteBuffer の読み込み時間は、0時間0分0秒299515847 ———— )
(○・ω・)ノ————- SeekableByteChannel の読み込み時間は、0時間0分0秒33603955100000005 ———— )
(○・ω・)ノ————- SeekableByteChannelDirectBuffer の読み込み時間は、0時間0分0秒351710028 ———— )
(○・ω・)ノ————- FilesReadAllBytes の読み込み時間は、0時間0分0秒38764014300000005 ———— )
テスト終了!
約1ギガバイト
テスト用一時ファイル作成開始
テスト用一時ファイルを C:\Users\Yucchi\AppData\Local\Temp\temp4417221917340211970.txt に作成します。
テスト用一時ファイルのサイズは、1048576026 バイトです。
(○・ω・)ノ————- FileInputStream の読み込み時間は、0時間0分0秒851719442 ———— )
(○・ω・)ノ————- BufferedInputStream の読み込み時間は、0時間0分0秒8790631670000001 ———— )
(○・ω・)ノ————- fileChannelOpen の読み込み時間は、0時間0分0秒6286216090000001 ———— )
(○・ω・)ノ————- fileChannelOpenDirectBuffer の読み込み時間は、0時間0分0秒62141002 ———— )
(○・ω・)ノ————- fileChannelByteBuffer の読み込み時間は、0時間0分0秒6036760210000001 ———— )
(○・ω・)ノ————- FileChannelDirectByteBuffer の読み込み時間は、0時間0分0秒6924091010000001 ———— )
(○・ω・)ノ————- FileChannelMappedByteBuffer の読み込み時間は、0時間0分0秒6346080350000001 ———— )
(○・ω・)ノ————- FileChannelOpenMappedByteBuffer の読み込み時間は、0時間0分0秒583061946 ———— )
(○・ω・)ノ————- SeekableByteChannel の読み込み時間は、0時間0分0秒6516133420000001 ———— )
(○・ω・)ノ————- SeekableByteChannelDirectBuffer の読み込み時間は、0時間0分0秒6945191980000001 ———— )
(○・ω・)ノ————- FilesReadAllBytes の読み込み時間は、0時間0分0秒74813046 ———— )
テスト終了!
約2ギガバイト
テスト用一時ファイル作成開始
テスト用一時ファイルを C:\Users\Yucchi\AppData\Local\Temp\temp4971076785814883678.txt に作成します。
テスト用一時ファイルのサイズは、2097152052 バイトです。
(○・ω・)ノ————- FileInputStream の読み込み時間は、0時間0分1秒8658922370000002 ———— )
(○・ω・)ノ————- BufferedInputStream の読み込み時間は、0時間0分1秒8456471320000001 ———— )
(○・ω・)ノ————- fileChannelOpen の読み込み時間は、0時間0分1秒3322223500000001 ———— )
(○・ω・)ノ————- fileChannelOpenDirectBuffer の読み込み時間は、0時間0分1秒25010529000000004 ———— )
(○・ω・)ノ————- fileChannelByteBuffer の読み込み時間は、0時間0分1秒21910027500000018 ———— )
(○・ω・)ノ————- FileChannelDirectByteBuffer の読み込み時間は、0時間0分1秒31621626700000016 ———— )
(○・ω・)ノ————- FileChannelMappedByteBuffer の読み込み時間は、0時間0分1秒21824110800000018 ———— )
(○・ω・)ノ————- FileChannelOpenMappedByteBuffer の読み込み時間は、0時間0分1秒150197747 ———— )
(○・ω・)ノ————- SeekableByteChannel の読み込み時間は、0時間0分1秒5578260060000002 ———— )
(○・ω・)ノ————- SeekableByteChannelDirectBuffer の読み込み時間は、0時間0分1秒35429876100000013 ———— )
(○・ω・)ノ————- FilesReadAllBytes の読み込み時間は、0時間0分1秒1966073290000001 ———— )
テスト終了!
だいたい想像していたとおりの結果となりました。
java.nio.channels.FileChannel クラスの public static FileChannel open(Path path, OpenOption… options) throws IOException を使って
ファイル・チャネルを取得して java.nio.MappedByteBuffer クラスを使って読み込むのが最速のようです。
ただし、java.nio.ByteBuffer クラスを使う処理では byteバッファの capacity(容量)をどれくらいに設定して良いのか解らなかったので適当にやったのでご容赦ください。
ネットで少しばかり調べたけど「これが BEST!」ってのは見当たらなかった。
今、ブログを書き終わろうとしているんだけど・・・
何故、こんなプログラムを組んでゴニョゴニョしようと思い立ったか思い出せずにモヤモヤしている。
TAGS: Java | 2016年2月21日8:24 PM
Trackback URL