检查文件夹是否包含文件

我有程序写入数据库文件夹已满或空。 现在我正在使用

bool hasFiles=false; (Directory.GetFiles(path).Length >0) ? hasFiles=true: hasFiles=false; 

但这需要将近一个小时,而我现在无能为力。

有没有最快的方法来检查文件夹是否有任何文件?

加速这种跨网络搜索的关键是减少网络上的请求数量。 而不是获取所有目录,然后检查每个目录,尝试通过一次调用获取所有内容。

在.NET 3.5中,没有一种方法可以递归获取所有文件和文件夹,因此您必须自己构建它(见下文)。 在.NET 4中,只需一步即可实现新的重载。

使用DirectoryInfo还可以获取有关返回的名称是文件还是目录的信息,这也会减少调用。

这意味着拆分所有目录和文件的列表就像这样:

 struct AllDirectories { public List DirectoriesWithoutFiles { get; set; } public List DirectoriesWithFiles { get; set; } } static class FileSystemScanner { public AllDirectories DivideDirectories(string startingPath) { var startingDir = new DirectoryInfo(startingPath); // allContent IList var allContent = GetAllFileSystemObjects(startingDir); var allFiles = allContent.Where(f => !(f.Attributes & FileAttributes.Directory)) .Cast(); var dirs = allContent.Where(f => (f.Attributes & FileAttributes.Directory)) .Cast(); var allDirs = new SortedList(dirs, new FileSystemInfoComparer()); var res = new AllDirectories { DirectoriesWithFiles = new List() }; foreach (var file in allFiles) { var dirName = Path.GetDirectoryName(file.Name); if (allDirs.Remove(dirName)) { // Was removed, so first time this dir name seen. res.DirectoriesWithFiles.Add(dirName); } } // allDirs now just contains directories without files res.DirectoriesWithoutFiles = new List(addDirs.Select(d => d.Name)); } class FileSystemInfoComparer : IComparer { public int Compare(FileSystemInfo l, FileSystemInfo r) { return String.Compare(l.Name, r.Name, StringComparison.OrdinalIgnoreCase); } } } 

实现GetAllFileSystemObjects取决于.NET版本。 在.NET 4上,它非常简单:

 ILIst GetAllFileSystemObjects(DirectoryInfo root) { return root.GetFileSystemInfos("*.*", SearchOptions.AllDirectories); } 

在早期版本中,还需要做一些工作:

 ILIst GetAllFileSystemObjects(DirectoryInfo root) { var res = new List(); var pending = new Queue(new [] { root }); while (pending.Count > 0) { var dir = pending.Dequeue(); var content = dir.GetFileSystemInfos(); res.AddRange(content); foreach (var dir in content.Where(f => (f.Attributes & FileAttributes.Directory)) .Cast()) { pending.Enqueue(dir); } } return res; } 

这种方法尽可能少地调用文件系统,在.NET 4上只调用一次,在早期版本的每个目录调用一次,允许网络客户端和服务器最小化底层文件系统调用和网络往返次数。

获取FileSystemInfo实例的缺点是需要多个文件系统操作(我相信这在某种程度上取决于操作系统),但是对于每个名称,任何解决方案都需要知道它是文件还是目录,因此在某种程度上这是不可避免的(不需要求助于P / Invoke of FindFileFirst / FindNextFile / FindClose )。


除此之外,使用分区扩展方法会更容易:

 Tuple,IEnumerable> Extensions.Partition( this IEnumerable input, Func parition); 

写那个懒惰将是一个有趣的练习(只有当某些东西在一个输出上迭代时才会消耗输入,同时缓冲另一个输出)。

要检查目录或子目录中是否存在任何文件,请在.net 4中使用以下方法:

 public bool isDirectoryContainFiles(string path) { if (!Directory.Exists(path)) return false; return Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories).Any(); } 

如果您使用.Net 4.0,请查看EnumerateFiles方法。 http://msdn.microsoft.com/en-us/library/dd413232(v=VS.100).aspx

EnumerateFiles和GetFiles方法的不同之处如下:使用EnumerateFiles时,可以在返回整个集合之前开始枚举FileInfo对象的集合; 当您使用GetFiles时,您必须等待返回整个FileInfo对象数组,然后才能访问该数组。 因此,当您使用许多文件和目录时,EnumerateFiles可以更高效。

这样就不会从文件夹中检索所有文件,如果枚举器至少有1个文件,则该文件夹不为空

我假设(虽然我不确定),因为你在网络驱动器上调用GetFiles(),它会增加大量时间从所有30k文件夹中检索所有文件并通过它们进行枚举。

我在CodeProject上找到了另一个目录枚举器,看起来很有前景。

或者……您可以在服务器上创建一个WebService,为您枚举所有内容并在之后返回结果。

编辑 :我认为您的问题更可能是文件夹访问。 每次访问网络驱动器中的目录时,您都将进行安全性和权限检查。 * 30k文件夹将是一个巨大的性能影响。 我非常怀疑使用FindFirstFile会有多大帮助,因为枚举的实际文件数量只会是0或1。

可能值得一提的是:

但这需要将近一个小时,而我现在无能为力 。 (重点补充)

你是在主要线程上从GUI应用程序这样做的吗? 如果是这样,请使用BackgroundWorker关闭此过程。 至少那时应用程序将继续响应。 您还可以在方法中添加CancellationPending检查,如果花费的时间过长则取消它。

与你的问题相关 – 只是我注意到并认为我会评论的东西。

最好的办法是使用API​​函数FindFirstFile。 它不会花费那么长的时间。