5

50,000個のパスのリストがあり、これらの各パスに対してファイルが存在するかどうかを確認する必要があります。現在、次のように各パスを個別に検証しています。

public static List<String> filesExist(String baseDirectory, Iterable<String> paths) throws FileNotFoundException{
        File directory = new File(baseDirectory);
        if(!directory.exists()){
            throw new FileNotFoundException("No Directory found: " + baseDirectory );
        }else{
            if(!directory.isDirectory())
                throw new FileNotFoundException(baseDirectory + " is not a directory!");
        }

        List<String> filesNotFound = new ArrayList<String>();

        for (String path : paths) {
            if(!new File(baseDirectory + path).isFile())
                filesNotFound.add(path);
        }
        return filesNotFound;
    }

50,000個のファイルオブジェクトを作成しないように改善する方法はありますか?私もグアバを使っています。exists()バルク方式で役立つユーティリティはありますか?

4

5 に答える 5

5

50,000個のFileオブジェクトの作成は、ほぼ確実にボトルネックではありません。実際のファイルシステム操作が、おそらくそれを遅くしている原因です。

私は2つの提案があります:

  1. チェックする前に、ファイルシステムキャッシュを最大限に活用するために、パスを場所で並べ替えます。
  2. サブディレクトリが存在しない場合は、その中のすべてのファイルとサブディレクトリも存在しないと自動的に想定できます。
于 2012-06-15T08:02:57.307 に答える
0

IMHOの非常に効率的なソリューション(以前の両方の回答に触発された)は次のようになります。

  • パスを並べ替える
  • それらのそれぞれをツリーと見なします
  • もう1つのツリーはディレクトリツリーです
  • ディレクトリツリーにアクセスするときは、他のツリーに「多くの」子がある場合はディレクトリ全体を読み取ります。それ以外の場合は、「少数の」子を個別にチェックします。
  • 両方のツリーを並行してトラバースし、一方に欠落している部分をスキップします

例(プレオーダーリストとして指定されたツリー):

tree1: / /a /a/a /d /d/a /d/a/b /e
tree2: / /a /b /d /d/a /e

処理:

  • 皮切りに/
  • /a両方に存在するので降りる
  • /a/atree2で欠落しているとしてスキップ
  • /btree1で欠落しているためスキップ
  • /d両方に存在するので降りる
  • ..。

リストfilesNotFoundは、入力リストに対応するツリーでスキップされたすべてのファイルで構成されます。

于 2012-06-15T09:15:07.463 に答える
0

以前のaixの回答には同意しますが、1つの観点を追加したいと思います。ファイルシステムアクセスがボトルネックであり、baseDirectoryの下のファイルの数が大まかにわかっていて、それほど多くない場合(それが意味するものは何でも)、FileUtils.iterateFilesまたはを試してからFileUtils.listFiles、返された各パスがパスに存在するかどうかを確認する価値があります。この背後にある考え方は、これらのメソッドが実行するディレクトリリストが多くの個別のアクセスよりも効率的である可能性があるということです。

繰り返しになりますが、このアプローチは環境に関する多くの仮定に依存しますが、常に考えて試してみる価値があります。

(これをaixの返信へのコメントとして追加したかったのですが、できませんでした...)

于 2012-06-15T08:29:19.117 に答える
0

理由により、現在開発環境を起動できないため、少し間違っている可能性があります。ゴーゴーガジェット関数型プログラミング!

public static List<String> filesExist(String baseDirectory, Iterable<String> paths) throws FileNotFoundException{
    final File base = new File(baseDirectory);
    if (base.exists()) {
        return FluentIterable.from(paths).filter(new Predicate<String>() {
            public boolean apply(String in) {
                return new File(in,base).exists();
            }
        }).toImmutableList();
    }
    throw new FileNotFoundException("Base doesn't exist!");
}

上で述べたように、あなたの主要な問題は依然としてI/Oです。

于 2012-06-15T13:15:09.733 に答える
0

これには特別なデータ構造を使用します。

TRIE

ここに画像の説明を入力してください

ターミナルノードをファイルおよびフォルダーを含むそれらの親と考えてください。フォルダのターミナルノードを確認できます。一部のファイルが同じ親を共有している場合、シーク操作の量が大幅に削減されます。

そして、あなたの総操作数は

トータルオペレーション=トータルノード-ターミナルノード

そして、単純なトラバーサルアルゴリズムでは、特別なツリーで十分です。申し訳ありませんが、このソリューションはGuavaに基づいていないが、より適切であると強く信じています。

于 2012-06-15T13:46:58.513 に答える