0

ディレクトリ内のすべてのファイルのサイズを計算する小さな関数を作成しました。実際の関数はさらに多くのことを行いますが、この例は簡潔にするために使用されています。

これは機能し、ディレクトリを再帰的にウォークするのは簡単ですが、すでに処理されているすべてのファイル名を除外したいと思います。内のすべてのファイル名を追跡して、ファイルListのサイズを取得する前に、ファイルがに存在するかどうかを確認し、存在する場合Listは除外する必要があるようにします。MD5チェックサムなどは必要ありません。私の状況では、ファイル名で十分です。

関数から返すことができる値は1つだけであり、Javaでは参照渡しが許可されていないため、これを実装するための最良の方法についてはかなり迷っています。これが私のコードです:

public static Long getFileSize(File dirDirectory) {
    Long lngSize = new Long(0);

    for (File filItem : dirDirectory.listFiles()) {
        if (filItem.isDirectory()) {
            lngSize += getFileSize(filItem);
        }
        else {
            //Is a file with the same filename alrwady been calculated
            //then exclude it
            //else
            //include it.
            lngSize += filItem.length();
        }
    }

    return lngSize;
}
4

6 に答える 6

3

を使用しないでください。Listを使用してくださいHashSet。リストはO(n)ルックアップを使用してファイルがそこにあるかどうかを確認しますが、aHashSetはを使用しますO(1)

メソッドをパブリックにし、ヘルパー関数をプライベートにすることで、HashSet実装をプログラムの残りの部分に公開しません(これは、それを気にしないし、気にしないでください)。

public static Long getFileSize(File dirDirectory) {
    return getFileSize(File dirDirectory, new HashSet<File>());
}

private static Long getFileSize(File dirDirectory, HashSet<File> prevProcess) {
    Long lngSize = new Long(0);

    for (File filItem : dirDirectory.listFiles()) {
        if (prevProcess.contains(filItem) continue;
        if (filItem.isDirectory()) {
            lngSize += getFileSize(filItem);
        }
        else {
            lngSize += filItem.length();
        }
        prevProcess.add(filItem);
    }

    return lngSize;
}
于 2012-11-06T20:00:26.003 に答える
1

あなたはこのようにそれを行うことができます:

public static Long getFileSize(File dirDirectory) {
    return getFileSize(dirDirectory, new HashSet<String>());
}

public static Long getFileSize(File dirDirectory, Set<String> previouslyProcessedFiles) {
    //DO IT HERE AS YOU WISH
}
于 2012-11-06T19:56:57.970 に答える
0

セットを渡す:

public static Long getFileSize(Set<File> alreadySeen, File dirDirectory) {
    long lngSize = 0;

    for (File filItem : dirDirectory.listFiles()) {
        if (filItem.isDirectory()) {
            lngSize += getFileSize(filItem);
        }
        else {
            //Is a file with the same filename alrwady been calculated
            //then exclude it
            //else
            //include it.
            if (! alreadySeen.contains(filItem.getName())) {
                alreadySeen.add(filItem.getName());
                lngSize += filItem.length();
            }
        }
    }
    return lngSize;
}

電話する:

Long size = getFileSize(new HashSet<File>(), myDirectory)

また、Javaが合計を継続的にアンボックス化/リボックス化する必要がないようにlongするよりも、カウンターを使用する方が適切です。Long

ちなみに、再帰せずにディレクトリツリーをたどるのは簡単です。遭遇したディレクトリをリストに追加して、後で処理するだけです。

public static Long getFileSize(File dirDirectory) {
    long lngSize = 0;
    Deque<File> unprocessedDirs = new ArrayDeque<File>();
    unprocessedDirs.add(dirDirectory);
    Set<File> alreadySeen = new HashSet<File>();
    while (!unprocessedDirs.isEmpty()) {
        File dir = unprocessedDirs.removeFirst();

        for (File filItem : dir.listFiles()) {
            if (filItem.isDirectory()) {
                unprocessedDirs.addFirst(filItem); 
            }
            else {
                //Is a file with the same filename alrwady been calculated
                //then exclude it
                //else
                //include it.
                if (! alreadySeen.contains(filItem.getName())) {
                    alreadySeen.add(filItem.getName());
                    lngSize += filItem.length();
                }
            }
        }
    }
    return lngSize;
}
于 2012-11-06T20:01:14.820 に答える
0

これはどう:

public static Long getFileSize(File dirDirectory, List<String> processed) {
    Long lngSize = new Long(0);

    for (File filItem : dirDirectory.listFiles()) {
        if (filItem.isDirectory()) {
            lngSize += getFileSize(filItem, processed);

        } else {
            String filName = filItem.getName();
            if (processed.contains(filName)) {
                continue;
            }
            lngSize += filItem.length();
            processed.add(filName);
        }
    }

    return lngSize;
}
于 2012-11-06T20:01:56.733 に答える
0

グローバル変数を使用するか、リストをパラメーターとして関数に渡すことができます。しかし、私の推奨事項は、リストではなく、セット、特にTreeSetまたはHashSetを使用することです。

重複を保存する必要はなく、リスト全体でファイル名を検索する必要があります。これは、リストO(n)での非常にコストのかかる操作です。セットは重複を防ぎますが、特にHashSetはO(n)で、TreeSetはO(ln n)です-検索がはるかに高速になります

参照:ハッシュセットとツリーセット

于 2012-11-06T20:02:42.660 に答える
0

組み込みのフィルターFileFilterまたはメソッドFilenameFilterを使用することをお勧めします。File.listFiles()このように、それはよりエレガントで直感的です。

public class FileSizeCalculator {

    public static void main(String[] args) {
        System.out.println(getFileSize(new File(".")));
    }

    public static Long getFileSize(File directory) {

        FileFilter uniqueFilter = new FileFilter() {
            Set<File> uniqueFiles = new HashSet<File>();
            @Override
            public boolean accept(File file) {
                /**
                 * This will return true only if this set 
                 * did not already contain the specified element
                 */
                return uniqueFiles.add(file);
            }
        };

        long size = 0L;
        for (File file : directory.listFiles(uniqueFilter)) {
            size += file.isDirectory() ? getFileSize(file) : file.length();
        }
        return size;
    }
}
于 2012-11-06T20:31:18.763 に答える