检查文件夹是否包含文件

use*_*618 5 c# directory

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

bool hasFiles=false;
(Directory.GetFiles(path).Length >0) ? hasFiles=true: hasFiles=false;
Run Code Online (Sandbox Code Playgroud)

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

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

Len*_*eng 10

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

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


Ric*_*ard 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);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

ILIst<FileSystemInfo> GetAllFileSystemObjects(DirectoryInfo root) {
  return root.GetFileSystemInfos("*.*", SearchOptions.AllDirectories);
}
Run Code Online (Sandbox Code Playgroud)

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

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;
}
Run Code Online (Sandbox Code Playgroud)

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

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


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

Tuple<IEnumerable<T>,IEnumerable<T>> Extensions.Partition<T>(
                                                 this IEnumerable<T> input,
                                                 Func<T,bool> parition);
Run Code Online (Sandbox Code Playgroud)

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