我有程序写入数据库文件夹已满或为空。现在我正在使用
bool hasFiles=false;
(Directory.GetFiles(path).Length >0) ? hasFiles=true: hasFiles=false;
但这需要将近一个小时,而且我现在无法做任何事情。
有没有最快的方法来检查文件夹是否有任何文件?
答案 0 :(得分:10)
要检查目录或子目录中是否存在任何文件,在.net 4中,您可以使用以下方法:
public bool isDirectoryContainFiles(string path) {
if (!Directory.Exists(path)) return false;
return Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories).Any();
}
答案 1 :(得分:5)
加速这种跨网络搜索的关键是减少网络上的请求数量。而不是获取所有目录,然后检查每个目录,尝试通过一次调用获取所有内容。
在.NET 3.5中,没有一种方法可以递归获取所有文件和文件夹,因此您必须自己构建它(见下文)。在.NET 4中,只需一步就可以实现新的重载。
使用DirectoryInfo
还可以获取有关返回的名称是文件还是目录的信息,这也会减少调用。
这意味着拆分所有目录和文件的列表就像这样:
struct AllDirectories {
public List<string> DirectoriesWithoutFiles { get; set; }
public List<string> DirectoriesWithFiles { get; set; }
}
static class FileSystemScanner {
public AllDirectories DivideDirectories(string startingPath) {
var startingDir = new DirectoryInfo(startingPath);
// allContent IList<FileSystemInfo>
var allContent = GetAllFileSystemObjects(startingDir);
var allFiles = allContent.Where(f => !(f.Attributes & FileAttributes.Directory))
.Cast<FileInfo>();
var dirs = allContent.Where(f => (f.Attributes & FileAttributes.Directory))
.Cast<DirectoryInfo>();
var allDirs = new SortedList<DirectoryInfo>(dirs, new FileSystemInfoComparer());
var res = new AllDirectories {
DirectoriesWithFiles = new List<string>()
};
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<String>(addDirs.Select(d => d.Name));
}
class FileSystemInfoComparer : IComparer<FileSystemInfo> {
public int Compare(FileSystemInfo l, FileSystemInfo r) {
return String.Compare(l.Name, r.Name, StringComparison.OrdinalIgnoreCase);
}
}
}
实现GetAllFileSystemObjects
取决于.NET版本。在.NET 4上,它非常简单:
ILIst<FileSystemInfo> GetAllFileSystemObjects(DirectoryInfo root) {
return root.GetFileSystemInfos("*.*", SearchOptions.AllDirectories);
}
在早期版本中,还需要做一些工作:
ILIst<FileSystemInfo> GetAllFileSystemObjects(DirectoryInfo root) {
var res = new List<FileSystemInfo>();
var pending = new Queue<DirectoryInfo>(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<DirectoryInfo>()) {
pending.Enqueue(dir);
}
}
return res;
}
这种方法尽可能少地调用文件系统,只在.NET 4上调用一次,或在早期版本的每个目录调用一次,允许网络客户端和服务器最小化底层文件系统调用和网络往返次数。
获取FileSystemInfo
实例的缺点是需要多个文件系统操作(我相信这在某种程度上取决于操作系统),但是对于每个名称,任何解决方案都需要知道它是文件还是目录,所以这是不可避免的在某种程度上(不使用FindFileFirst
/ FindNextFile
/ FindClose
的P / Invoke。)
除此之外,使用分区扩展方法会更容易:
Tuple<IEnumerable<T>,IEnumerable<T>> Extensions.Partition<T>(
this IEnumerable<T> input,
Func<T,bool> parition);
写那个懒惰是一个有趣的练习(只有当某些东西在其中一个输出上迭代时才会消耗输入,同时缓冲另一个输出)。
答案 2 :(得分:4)
如果您使用.Net 4.0,请查看EnumerateFiles方法。 http://msdn.microsoft.com/en-us/library/dd413232(v=VS.100).aspx
EnumerateFiles和GetFiles 方法的不同之处如下:当你 使用EnumerateFiles,你就可以开始了 枚举FileInfo的集合 整个集合之前的对象 回;当你使用GetFiles时,你 必须等待整个阵列 要返回的FileInfo对象 在您可以访问阵列之前。 因此,当你工作时 许多文件和目录, EnumerateFiles可以更有效。
这样就不会从文件夹中检索所有文件,如果枚举器至少有1个文件,则该文件夹不为空
答案 3 :(得分:3)
我假设(虽然我不确定),因为你在网络驱动器上调用GetFiles(),它会增加大量时间从所有30k文件夹中检索所有文件并通过它们进行枚举。
我在CodeProject上找到了另一个目录枚举器here,看起来很有希望。
或者......你可以在服务器上创建一个WebService,为你枚举所有内容并在之后返回结果。
编辑:我认为您的问题更有可能是文件夹访问权限。每次访问网络驱动器中的目录时,您都将进行安全性和权限检查。 * 30k文件夹将成为一个重大的性能。我非常怀疑使用FindFirstFile会有多大帮助,因为枚举的文件实际数量只会是0或1。
答案 4 :(得分:2)
可能值得一提:
但是这需要将近一个小时,我现在无法做任何事情。 (重点补充)
你是在主要线程的GUI应用程序中这样做的吗?如果是这样,请使用BackgroundWorker
吐出此过程。至少那时应用程序将继续响应。您还可以在方法中添加CancellationPending
的检查,如果花费的时间过长则取消它。
与你的问题相关 - 只是我注意到并认为我会评论的内容。
答案 5 :(得分:0)
您最好的选择是使用API函数FindFirstFile。它不会花费那么长的时间。