我正在使用VSTS 2008 + C#+ .Net 3.5来开发控制台应用程序。我需要枚举当前文件夹中最近的50个文件(读取文件内容,获取文件元数据,如文件名,创建时间等)。由于当前文件夹有大约5,000个文件,并且如果我使用Directory.GetFiles API,所有5,000个文件的元数据信息将被读入内存。我认为这是一种浪费,因为我只需要访问最近的50个文件。
任何解决方案只能访问当前目录中的50个最新文件?
答案 0 :(得分:3)
此解决方案仍会加载有关所有文件的元数据,但我认为它对于大多数用途来说足够快。以下代码报告在Windows \ System32目录(~2500个文件)中枚举50个最近更新的文件大约需要50毫秒。除非代码运行频繁,否则我可能不会花时间优化它:
FileInfo[] files = (new DirectoryInfo(@"C:\WINDOWS\System32")).GetFiles();
Stopwatch sw = new Stopwatch();
sw.Start();
IEnumerable<FileInfo> recentFiles = files.OrderByDescending(
fi => fi.LastWriteTime).Take(50);
List<FileInfo> list = recentFiles.ToList();
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
list.ForEach(fi => Console.WriteLine(fi.Name));
<强>更新强>
基于有关在文件名中使用日期/时间的注释中的讨论:请注意Directory.GetFiles
不会加载有关文件的元数据;它只返回一个带文件名的字符串数组(DirectoryInfo.GetFiles
另一方面返回FileInfo
个对象的数组)。因此,如果您的文件名中有日期和时间(最好采用适合排序的格式,例如yyyyMMdd-HHmmss
或类似的东西),您可以使用Directory.GetFiles
来获取文件名,排序下降,然后从列表中首先选择50:
string[] files = Directory.GetFiles(pathToLogFiles);
IEnumerable<string> recentFiles = files.OrderByDescending(s => s).Take(50);
List<string> recentFiles = recentFiles.ToList();
然后遍历列表并从每个文件加载所需的任何数据。
答案 1 :(得分:1)
我真的不确定它值得你这么做...考虑以下程序:
class DateCompare : IComparer<FileInfo>
{
public int Compare(FileInfo a, FileInfo b)
{
int result = a.LastWriteTime.CompareTo(b.LastWriteTime);
if (result == 0)
return StringComparer.OrdinalIgnoreCase.Compare(a.FullName, b.FullName);
return result;
}
}
public static void Main(string[] args)
{
DirectoryInfo root = new DirectoryInfo("c:\\Projects\\");
DateTime start = DateTime.Now;
long memory = GC.GetTotalMemory(false);
FileInfo[] allfiles = root.GetFiles("*", SearchOption.AllDirectories);
DateTime sortStart = DateTime.Now;
List<FileInfo> files = new List<FileInfo>(20000);
IComparer<FileInfo> cmp = new DateCompare();
foreach (FileInfo file in allfiles)
{
int pos = ~files.BinarySearch(file, cmp);
files.Insert(pos, file);
}
Console.WriteLine("Count = {0:#,###}, Read = {1}, Sort = {2}, Memory = {3:#,###}", files.Count, sortStart - start, DateTime.Now - sortStart, GC.GetTotalMemory(false) - memory);
}
这是上述程序的输出:
Count = 16,357, Read = 00:00:03.5793579, Sort = 00:00:06.7776777, Memory = 5,758,976 Count = 16,357, Read = 00:00:03.2173217, Sort = 00:00:06.1616161, Memory = 7,339,920 Count = 16,357, Read = 00:00:03.5083508, Sort = 00:00:06.7556755, Memory = 10,346,504
在3秒内运行,分配5~10mb,同时抓取6,931个目录并返回16k文件名。这是你谈论的音量的三倍,我打赌大部分时间都在抓取目录树(我没有一个包含5k文件的目录)。如果你可以通过匹配我建议的文件名来丢弃文件,那么最糟糕的费用总是那样。