[英]C# - How to generate a list of file names and sub directories in a directory with creation date
我正在尝试生成目录及其子目录中存在的所有文件的列表以及其创建日期。 日期和文件名,用“ ::”分隔
我尝试了下面的代码,但是当文件数量巨大时,它会花费一些时间。 谁能建议我一个更好的方法/优化代码?
对于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();
var dirinfo = new DirectoryInfo( "c:\path" );
var entries = dirinfo.GetFileSystemInfos( "*.*", SearchOption.AllDirectories )
.Select( t => string.Format( "{0}::{1}", t.FullName, t.CreationTime );
或者,当您只是寻找路径时
Directory.GetFiles("C:\\", "*", SearchOption.AllDirectories)
.ToList()
.ForEach(Console.WriteLine);
您确实应该使用新的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真是令人b目结舌。 但是, 您可以编写自己的类来枚举文件系统,而不会带来太多麻烦 。 这是我刚刚写的,您可以使用它,它仅使用.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秒钟内完成。
希望这可以帮助你!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.