Java大ファイルインスタンス分析の効率的な読み取り

3169 ワード

1、概要
このチュートリアルでは、Javaで大きなファイルを効率的に読み込む方法を説明します.Java――基礎に戻る.
2、メモリに読み込む
ファイル行を読み込む標準的な方法は、メモリで読み取ることです.GuavaとApacheCommonsIOでは、次のようにファイル行をすばやく読み取る方法が用意されています.Files.readLines(new File(path), Charsets.UTF_8); FileUtils.readLines(new File(path));
この方法による問題は,ファイルのすべての行がメモリに格納され,ファイルが十分に大きいとすぐにプログラムがOutOfMemoryError異常を放出することである.
たとえば、約1 Gのファイルを読み込みます.

@Test
public void givenUsingGuava_whenIteratingAFile_thenWorks() throws IOException {
  String path = ...
  Files.readLines(new File(path), Charsets.UTF_8);
}

この方式は、最初はわずかなメモリしか消費されませんでした:(約0 Mbのメモリを消費しました)

[main] INFO org.baeldung.java.CoreJavaIoUnitTest - Total Memory: 128 Mb
[main] INFO org.baeldung.java.CoreJavaIoUnitTest - Free Memory: 116 Mb

しかし、ファイルがすべてメモリに読み込まれると、最後に見ることができます(約2 GBのメモリが消費されています):

[main] INFO org.baeldung.java.CoreJavaIoUnitTest - Total Memory: 2666 Mb
[main] INFO org.baeldung.java.CoreJavaIoUnitTest - Free Memory: 490 Mb

これは、このプロセスに約2.1 GBのメモリが消費されることを意味します.理由は簡単です.ファイルのすべての行がメモリに格納されています.
ファイルのすべての内容をメモリに格納すると、実際に使用可能なメモリがどれだけ大きくても、すぐに使用可能なメモリが消費されます.
また、通常、ファイルのすべての行を一度にメモリに入れる必要はありません.逆に、ファイルの各行を巡り、対応する処理を行い、処理が終わったら捨てます.だから、これは私たちがしなければならないことです.すべてのローをメモリに置くのではなく、ローを反復します.
3、ファイルフロー
次に、java.util.Scannerクラスを使用してファイルの内容をスキャンし、1行1行連続で読み取ります.

FileInputStream inputStream = null;
Scanner sc = null;
try {
  inputStream = new FileInputStream(path);
  sc = new Scanner(inputStream, "UTF-8");
  while (sc.hasNextLine()) {
    String line = sc.nextLine();
    // System.out.println(line);
  }
  // note that Scanner suppresses exceptions
  if (sc.ioException() != null) {
    throw sc.ioException();
  }
} finally {
  if (inputStream != null) {
    inputStream.close();
  }
  if (sc != null) {
    sc.close();
  }
}

このスキームは、ファイル内のすべてのローを巡回します.各ローの参照を維持することなく、各ローを処理できます.とにかくメモリに保存されていません:(約150 MBのメモリを消費しました)
[main]INFOorg.baeldung.java.CoreJavaIoUnitTest-TotalMemory:763Mb
[main]INFOorg.baeldung.java.CoreJavaIoUnitTest-FreeMemory:605Mb
4、ApacheCommonsIOフロー
CommonsIOライブラリを使用して実装することもできます.このライブラリが提供するカスタムLineIteratorを使用します.

LineIterator it = FileUtils.lineIterator(theFile, "UTF-8");
try {
  while (it.hasNext()) {
    String line = it.nextLine();
    // do something with line
  }
} finally {
  LineIterator.closeQuietly(it);
}

ファイル全体がメモリに格納されていないため、かなりの保存メモリ消費量が発生します.(約150 MBのメモリ消費量)
[main]INFOo.b.java.CoreJavaIoIntegrationTest-TotalMemory:752Mb
[main]INFOo.b.java.CoreJavaIoIntegrationTest-FreeMemory:564Mb
5、結論
この短文では、読み取りを繰り返さず、メモリを消費しないで大きなファイルを処理する方法について説明します.これは、大きなファイルの処理に役立つ解決策を提供します.
これらの例の実装とコードフラグメントはすべて私のgithubプロジェクトで取得できます.これはEclipseベースのプロジェクトなので、インポートと実行が容易であるはずです.
以上がJavaの大ファイルインスタンス解析の効率的な読み取りに関するすべての内容であり,皆さんの役に立つことを願っています.興味のある方は引き続き当駅の他の関連テーマを参照することができます.不足点があれば、伝言を歓迎します.友达の本駅に対する支持に感谢します!