如何改进此SUPERFAST目录大小查找器?

时间:2016-03-04 11:03:44

标签: c# parallel-processing directory size

我有几个大型目录(由于遗留原因我无法进行重组)。

一个典型的目录可能包含150K个子目录,每个子目录都有嵌套目录,也可能是4K文件。

我无法从Windows资源管理器或通过cygwin使用du获取目录大小。这些都只是持续处理数小时。

我已经编写了自己的代码来解决这个问题 - 而我所拥有的代码对于较小的文件夹来说速度非常快 - 但对于这些大型文件夹来说仍然很慢。

任何人都可以改进吗?

(如果你有一个完全不同的解决方案,我也很高兴听到它。)

var size = GetDirectorySize3b(@"C:\MyMassiveFolder");

        public long GetDirectorySize3b(string parentDirectory)
        {
            Int64 ttl = 0;
            Stopwatch sw = new Stopwatch();
            var dirs = Directory.GetDirectories(parentDirectory);
            var llDirs = SplitIntoLists(dirs.ToList<string>(), 10);
            ttl = ParallelDirSizeLLS(llDirs);
            return ttl;

        }

        public List<List<string>> SplitIntoLists(List<string> l, int numLists)
        {
            List<List<string>> lls = new List<List<string>>();

            int listLength = l.Count/numLists + 1;
            for (int i = 0; i < l.Count; i += listLength)
            {
                var partL = l.Skip(i).Take(listLength).ToList<string>();
                lls.Add(partL);
            }

            return lls;
        }

        public long ParallelDirSizeLLS(List<List<string>> lls)
        {

            _size = 0;

            Parallel.ForEach(lls,
                //new ParallelOptions { MaxDegreeOfParallelism = 30 },
                ParallelDirSizeL);

            return _size;
        }

        private void ParallelDirSizeL(List<string> l)
        {
            foreach (var dir in l)
            {

                var ds = GetDirectorySize3(dir);
                Interlocked.Add(ref _size, ds);
            }
        }

        public long GetDirectorySize3(string parentDirectory)
        {
            Scripting.FileSystemObject fso = new Scripting.FileSystemObject();
            Scripting.Folder folder = fso.GetFolder(parentDirectory);
            Int64 dirSize = (Int64)folder.Size;

            Marshal.ReleaseComObject(fso);

            return dirSize;
        }

6 个答案:

答案 0 :(得分:1)

我不确定解决方案,但也许您可以尝试使用Microsoft Indexing Service?它存储有关所有索引文件的信息,包括大小。

我找到了一些信息: http://www.thejoyofcode.com/Using_Windows_Search_in_your_applications.aspx

答案 1 :(得分:1)

由于存储设备同步执行I / O操作,因此您将无法通过读取操作的并行化获得任何速度优势。

您的方法可能是尽可能多地缓存到RAM中,然后并行处理。我在项目上使用的方法,我在NTFS上使用文件进行操作是缓存 MFT记录。但是,我们手写的文件系统解析代码中包含了大量的工时,这对您来说不是解决方案。

所以你可能想尝试找到适合你的源代码。这个link提到了NTFS的两个开源快速搜索实现,您可能会看到它们,因为它们完成了一切:在内存中缓存MFT以进行超快速搜索。它们不直接解决您的问题,但似乎有该方法的源代码。

这是非常低级别的解决方案,但在我看来,每个其他方法都会有类似于已经讨论过的结果,因为处理文件或文件夹的每个操作都会尝试按记录读取MFT记录,通常大小为1KB。但是,磁盘处理一个,比如2MB读取操作,然后是2048个1KB操作。读取记录也可以在物理上彼此靠近,在这种情况下,缓存也是一个好处。 提到的产品用于搜索。但您可以使用他们的代码来确定文件&#39;尺寸。

答案 2 :(得分:1)

为什么不使用FileSystemWatcher监视目录并预先确定查询大小?也许在顶级目录中创建一个SQLite文件,并拥有一个包含所有文件和属性的表,包括大小。如果创建/修改/删除了文件,FileSystemWatcher可以通知您的应用程序,您可以更新数据库以进行快速查询。这只是一个想法。

答案 3 :(得分:0)

这个基本的java类:

import java.io.File;
import java.util.concurrent.atomic.AtomicLong;

public class DirSize {

    private static AtomicLong l = new AtomicLong();
    private static AtomicLong files = new AtomicLong();
    private static AtomicLong dirs = new AtomicLong();

    public static void recurse(File f) {
        if(f==null) {
            return;
        }
        if(f.isDirectory()) {
            dirs.getAndIncrement();
            if(f.listFiles()==null) {
                return;
            }
            for(File fc : f.listFiles()) {
                recurse(fc);
            }
        } else {
            files.getAndIncrement();
            l.getAndAdd(f.length());
        }
    }

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        recurse(new File("/usr"));
        long end = System.currentTimeMillis();
        System.out.println(end-start+" ms");
        System.out.println(files.get()+" files");
        System.out.println(dirs.get()+" dirs");
        System.out.println("size: "+l.get());
        System.out.println("size: "+(l.get()/(1024*1024))+" MB");
        double secs = (double)(end-start) / 1000d;
        double f = (double)files.get();
        System.out.println(Math.round(f/secs)+" files/s ");
    }

}

给了我:

11631 ms
386589 files
33570 dirs
size: 93068412461
size: 88756 MB
33238 files/s 

首次运行(但操作系统未重新启动)。这是macbook pro上的macOS,带有顺序读取和写入超过700 MB / s的SSD,这里的点可能比SSD基本上没有寻道时间的事实要少,因为读取文件大小是IOP,但是一个小小的。

你在运行什么磁盘?什么文件系统?它必须是窗户吗?

答案 4 :(得分:0)

实际上我建议你采取一种非常不同的方法来解决问题。

我的解决方案基于收集文件夹所包含的文件名的方式。获取子文件夹和文件的os依赖方法对于大量文件来说相对较慢,因此您应该直接进入底层文件系统并从那里读取文件结构。

大多数Windows操作系统驱动器FS都是NTFS,并且有一个非常高效的库来直接读取FS,我将链接到库的源代码以及如何在注释中使用它的示例。 但是

答案 5 :(得分:0)

我通常使用Tree Size的免费版本来获取海量文件夹结构的大小。它花了很长时间,但到目前为止一直在提供:

TreeSize Free