巨大なディレクトリを巡回する際の Java のパフォーマンス低下を回避する方法はありますか? 質問する

巨大なディレクトリを巡回する際の Java のパフォーマンス低下を回避する方法はありますか? 質問する

ネットワーク上に保存されているファイルを 1 つずつ処理しようとしています。バッファリングによりファイルの読み取りは高速ですが、問題は発生していません。問題は、フォルダー内のディレクトリを一覧表示することです。フォルダーごとに少なくとも 10,000 個のファイルがあり、フォルダーの数も多数あります。

File.list() は反復可能オブジェクトではなく配列を返すため、パフォーマンスが非常に低くなります。Java はフォルダー内のすべての名前を収集し、配列にパックしてから返します。

このバグのエントリはhttps://bugs.java.com/bugdatabase/view_bug;jsessionid=db7fcf25bcce13541c4289edeb4?bug_id=4285834回避策はありません。JDK7 ではこれが修正されたとだけ言われています。

いくつかの質問:

  1. このパフォーマンスのボトルネックを回避する方法を知っている人はいますか?
  2. 不可能なことをしようとしているのでしょうか? ディレクトリを反復処理するだけでも、パフォーマンスは低下するのでしょうか?
  3. プロジェクト全体をビルドしなくても、この機能を備えたベータ版 JDK7 ビルドを使用できますか?

ベストアンサー1

あまりきれいではありませんが、私はアプリを起動する前に dir/ls の出力をファイルにパイプし、ファイル名を渡すことで、この種の問題を解決したことがあります。

アプリ内で実行する必要がある場合は、system.exec() を使用することもできますが、問題が発生する可能性があります。

質問です。最初の形式は非常に高速になりますが、2 番目の形式もかなり高速になるはずです。

選択したコマンドの 1 行に 1 つの項目 (裸、装飾なし、グラフィックなし)、フル パス、および再帰オプションを必ず実行してください。

編集:

ディレクトリリストを取得するだけで 30 分もかかるなんてすごいですね。

exec() を使用すると、stdout をファイルに書き込む代わりにパイプにリダイレクトできることに気付きました。

これを実行すると、すぐにファイルの取得が開始され、コマンドが完了する前に処理を開始できるようになります。

実際にやり取りによって処理速度が遅くなる可能性もありますが、そうならない可能性もあります。試してみる価値はあるでしょう。

わあ、ちょうど .exec コマンドの構文を探していたところ、これを見つけました。おそらく、まさにあなたが求めていたものと同じでしょう (exec と "ls" を使用してディレクトリを一覧表示し、その結果をプログラムにパイプして処理します)。ウェイバックの良いリンク(ヨルグはコメントでこれですオラクルが壊した太陽から

とにかく、アイデアは単純ですが、コードを正しく書くのは面倒です。インターネットからコードを盗んでハックしてみます。


/**
 * 注意: これは最後の手段としてのみ使用してください。これはWindowsに固有のものであり、
 * それは良い解決策ではありませんが、高速であるはずです。
 *
 * これを使用するには、FileProcessorを拡張し、リストでprocessFiles("...")を呼び出します。
 * オプションは /s のようにしたい場合... /b を強くお勧めします
 *
 * processFile をオーバーライドすると、出力の各行ごとに 1 回呼び出されます。
 */
java.io.* をインポートします。

パブリック抽象クラス FileProcessor
{
   パブリック void processFiles(String dirOptions)
   {
      プロセス theProcess = null;
      BufferedReader inStream = null;

      // Helloクラスを呼び出す
      試す
      {
          theProcess = Runtime.getRuntime().exec("cmd /c dir " + dirOptions);
      }
      IOException をキャッチします
      {
         System.err.println("exec() メソッドでエラーが発生しました");
         e.printStackTrace();  
      }

      // 呼び出されたプログラムの標準出力ストリームから読み取る
      試す
      {
         inStream = 新しいBufferedReader(
                                新しい InputStreamReader( theProcess.getInputStream() ));  
         プロセスファイル(inStream.readLine());
      }
      IOException をキャッチします
      {
         System.err.println("inStream.readLine() でエラーが発生しました");
         e.printStackTrace();  
      }

   } // メソッド終了
   /** このメソッドをオーバーライドします。ファイルごとに 1 回呼び出されます */
   パブリック抽象 void processFile(String filename);


} // クラス終了

そして、コード提供者に感謝しますIBM

おすすめ記事