【问题标题】:C# - How to generate a list of file names and sub directories in a directory with creation dateC# - 如何在具有创建日期的目录中生成文件名和子目录列表
【发布时间】:2011-09-22 13:16:28
【问题描述】:

我正在尝试生成目录及其子目录中存在的所有文件及其创建日期的列表。日期和文件名用“::”隔开

我尝试了下面的代码,但是当文件数量很大时它会花费一些时间。谁能建议我更好的方法/优化代码??

对于 C 驱动器中的某些文件,我什至通过以下方法获得了“拒绝访问文件”异常。

DirectoryInfo dir1 = new DirectoryInfo(path);
DirectoryInfo[] dir = dir1.GetDirectories();
StreamWriter write = new StreamWriter("Test.lst");
foreach (DirectoryInfo di in dir)
{
    try
    {
        FileInfo[] file = di.GetFiles("*", SearchOption.AllDirectories);

        foreach (var f in file)
        {
            write.WriteLine(f.FullName + "::" + f.CreationTime.ToShortDateString());
        }
    }
    catch
    {
    }
}
write.Flush();
write.Close();

【问题讨论】:

  • 我在下面更新了我的答案,提供了一个适合您的解决方案。

标签: c# file directory


【解决方案1】:
var dirinfo = new DirectoryInfo( "c:\path" );
var entries = dirinfo.GetFileSystemInfos( "*.*", SearchOption.AllDirectories )
    .Select( t => string.Format( "{0}::{1}", t.FullName, t.CreationTime );

【讨论】:

  • 我使用的是 .NET 3.5 版并且 SearchOption.AllDirectories 参数不适用于 GetFileSystemInfos,因此它没有列出子目录中的文件。您能否提供一些不同的方法。
【解决方案2】:

或者当你只是在寻找你可以做的路径时

Directory.GetFiles("C:\\", "*", SearchOption.AllDirectories)
                .ToList()
                .ForEach(Console.WriteLine);

【讨论】:

    【解决方案3】:

    您确实应该使用新的EnumerateFiles 重载以避免将整个列表放入内存。

    foreach (var f in di.EnumerateFiles("*", SearchOption.AllDirectories)) {
        write.WriteLine(f.FullName + "::" + f.CreationTime.ToShortDateString());
    }
    

    您可以通过编写枚举的每一行来进一步优化您的代码。您可以一起避免流操作。您的整个例程只需几行代码:

    public static void GenerateList(String dirPath, String fileName) {
        var dir1 = new DirectoryInfo(dirPath);
    
        try {
            var lines = from f in dir1.EnumerateFileSystemInfos("*", SearchOption.AllDirectories)
                        select f.FullName + "::" + f.CreationTime.ToShortDateString();
    
            File.WriteAllLines(fileName, lines);
        }
        catch (Exception ex) {
            Console.WriteLine(ex);
        }
    }
    

    更新

    好的,所以没有 .Net 4.0 真是太可惜了。但是,您可以编写自己的类来枚举文件系统,而不会有太多麻烦。这是我刚刚写的一个你可以玩的,它只使用 .Net 3.5

    已经可用的 API 调用
    public class FileSystemInfoEnumerator: IEnumerator<FileSystemInfo>, IEnumerable<FileSystemInfo> {
      private const string DefaultSearchPattern = "*.*";
    
      private String InitialPath { get; set; }
      private String SearchPattern { get; set; }
      private SearchOption SearchOptions { get; set; }
      private Stack<IEnumerator<FileSystemInfo>> EnumeratorStack { get; set; }
    
      private Action<Exception> ErrorHandler { get; set; }
    
      public FileSystemInfoEnumerator(String path, String pattern = DefaultSearchPattern, SearchOption searchOption = SearchOption.TopDirectoryOnly, Action<Exception> errorHandler = null) {
    
         if (String.IsNullOrWhiteSpace(path))
            throw new ArgumentException("path cannot be null or empty");
    
         var dirInfo = new DirectoryInfo(path);
    
         if(!dirInfo.Exists)
            throw new InvalidOperationException(String.Format("File or Directory \"{0}\" does not exist", dirInfo.FullName));
    
         InitialPath = dirInfo.FullName;
         SearchOptions = searchOption;
    
         if(String.IsNullOrWhiteSpace(pattern)) {
            pattern = DefaultSearchPattern;
         }
    
         ErrorHandler = errorHandler ?? DefaultErrorHandler;
         EnumeratorStack = new Stack<IEnumerator<FileSystemInfo>>();
         SearchPattern = pattern;
         EnumeratorStack.Push(GetDirectoryEnumerator(new DirectoryInfo(InitialPath)));
      }
    
      private void DefaultErrorHandler(Exception ex) {
         throw ex;
      }
    
      private IEnumerator<FileSystemInfo> GetDirectoryEnumerator(DirectoryInfo directoryInfo) {
         var infos = new List<FileSystemInfo>();
    
         try {
            if (directoryInfo != null) {
               var info = directoryInfo.GetFileSystemInfos(SearchPattern);
               infos.AddRange(info);
            }
         } catch (Exception ex) {
            ErrorHandler(ex);
         }
    
         return infos.GetEnumerator();
      }
    
      public void Dispose() {
         foreach (var enumerator in EnumeratorStack) {
            enumerator.Reset();
            enumerator.Dispose();
         }
      }
    
      public bool MoveNext() {
         var current = Current;
    
         if (ShouldRecurse(current)) {
            EnumeratorStack.Push(GetDirectoryEnumerator(current as DirectoryInfo));
         }
    
         var moveNextSuccess = TopEnumerator.MoveNext();
    
         while(!moveNextSuccess && TopEnumerator != null) {
            EnumeratorStack.Pop();
    
            moveNextSuccess = TopEnumerator != null && TopEnumerator.MoveNext();
         }
    
         return moveNextSuccess;
      }
    
      public void Reset() {
         EnumeratorStack.Clear();
         EnumeratorStack.Push(GetDirectoryEnumerator(new DirectoryInfo(InitialPath)));
      }
    
      public FileSystemInfo Current {
         get {
            return TopEnumerator.Current;
         }
      }
    
      object IEnumerator.Current {
         get {
            return Current;
         }
      }
    
      public IEnumerator<FileSystemInfo> GetEnumerator() {
         return this;
      }
    
      IEnumerator IEnumerable.GetEnumerator() {
         return GetEnumerator();
      }
    
      IEnumerator<FileSystemInfo> TopEnumerator {
         get {
            if(EnumeratorStack.Count > 0)
               return EnumeratorStack.Peek();
    
            return null;
         }
      }
    
      private Boolean ShouldRecurse(FileSystemInfo current) {
         return current != null &&
                IsDirectory(current) &&
                SearchOptions == SearchOption.AllDirectories;
      }
    
      private Boolean IsDirectory(FileSystemInfo fileSystemInfo) {
         return fileSystemInfo != null &&
                (fileSystemInfo.Attributes & FileAttributes.Directory) == FileAttributes.Directory;
      }
    }
    

    使用它非常简单,只需使用您想要的选项对其进行实例化,然后像使用任何IEnumerable 一样使用它。

    var fileSystemEnumerator = new FileSystemInfoEnumerator("C:\\Dir", 
        searchOption: SearchOption.AllDirectories,
        errorHandler: Console.WriteLine);
    
    var lines = from f in fileSystemEnumerator
                select f.FullName + "::" + f.CreationTime.ToShortDateString();
    
    File.WriteAllLines("FileNames.txt", lines);
    

    现在显然这不如 .Net 4.0 高效,但内存占用应该是可以接受的。 我在一个包含 50K+ 文件的目录上进行了测试,它在大约 5 秒内完成。

    希望对你有所帮助!

    【讨论】:

    • 我使用的是 .NET 3.5,我无法使用 EnumerateFiles :-(
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-23
    • 2017-04-06
    • 1970-01-01
    • 1970-01-01
    • 2011-05-01
    • 2017-05-09
    相关资源
    最近更新 更多