我知道那里有重复项,但是我尝试了大约10种方法,需要6ms到29ms之间的时间,每个文件夹平均需要大约10ms才能从返回的路径中解析出文件的名称。 Directory.GetDirectories()
。
我找到的最快System.IO.Path.GetFileName(fullPath)
,但只有string.SubString(string.LastIndexOf(@"\")
的短暂余量;
我正在编写更好的Windows资源管理器版本,但展开C:\
并显示所有子文件夹大约需要半秒钟。半秒可能看起来不多,但是Windows和我看过的另一个程序会立即显示它。
我唯一能想到的是索引文件并将索引存储为XML,我想这可以在启动时完成。
我很好奇Windows和其他控件如何在同一台PC上更快地完成它。 C#和托管代码是否比非托管C ++慢?
更新
这是一个日志条目的示例,我意识到使用File.AppendAllText必须打开和关闭文件,但是许多操作只需要1毫秒来完成这个,所以唯一的缓慢时间是SetDirectoryName,这是做得像:
public void LoadChildNodes()
{
// clear the child nodes
this.ChildPanel.Controls.Clear();
// if this path exists
if (Directory.Exists(this.Path))
{
// get the log
WriteLogEntry("After Path Exists: " + stopWatch.Elapsed.Milliseconds.ToString());
// get the directories for this node
string[] tempDirectories = Directory.GetDirectories(this.Path);
// get the log
WriteLogEntry("After GetDirectories: " + stopWatch.Elapsed.Milliseconds.ToString());
// if there rae one or more directories
if ((tempDirectories != null) && (tempDirectories.Length > 0))
{
// reverse the list
List<string> directories = new List<string>();
// iterate the strings
foreach (string tempDirectory in tempDirectories)
{
// add this item
directories.Add(tempDirectory);
}
// now set the directories
directories.Reverse();
// log the time
WriteLogEntry("After Reverse Directories: " + stopWatch.Elapsed.Milliseconds.ToString());
// iterate the directory names
foreach (string directory in directories)
{
// log the time
WriteLogEntry("After Start Iterate New Directory: " + stopWatch.Elapsed.Milliseconds.ToString());
// create the childNode
ExplorerTreeNode childNode = new ExplorerTreeNode();
// the path for folders is the same as the name
string directoryName = System.IO.Path.GetFileName(directory);
// log the time
WriteLogEntry("After set directory name: " + stopWatch.Elapsed.Milliseconds.ToString());
// setup the node
childNode.SetupNode(directoryName, NodeTypeEnum.Folder, this.IconManager, this.Font, path);
// log the time
WriteLogEntry("After Setup Node" + stopWatch.Elapsed.Milliseconds.ToString());
// add this node
this.ChildPanel.Controls.Add(childNode);
// log the time
WriteLogEntry("After Add childNode to Controls: " + stopWatch.Elapsed.Milliseconds.ToString());
// dock to top
childNode.Dock = DockStyle.Top;
// log the time
WriteLogEntry("After Dock: " + stopWatch.Elapsed.Milliseconds.ToString());
}
// finished loading child nodes
stopWatch.Stop();
WriteLogEntry("Finished loading child nodes: " + stopWatch.Elapsed.Milliseconds.ToString());
}
}
}
我试图避免购买一个控件,所以我可以让项目开源,但我想我会买它并只给可执行文件。
路径存在之后:1 GetDirectories之后:2 反向目录后:3 开始迭代新目录后:3 设置目录名后:20 安装Node21后 将childNode添加到Controls后:21 在码头之后:22 开始迭代新目录后:22 设置目录名后:29 安装Node29之后 将childNode添加到Controls后:30 码头之后:30 开始迭代新目录后:30 设置目录名后:37 安装Node38后 将childNode添加到Controls后:38 码头之后:39 开始迭代新目录后:39
答案 0 :(得分:2)
首先,Windows资源管理器实现对FAT表的直接访问。这提供了相当大的速度。
其次,它使用缓存和挂钩组合更改通知。这允许它知道其他应用程序/窗口何时创建文件和目录。
因为它在启动时启动,所以它能够预先获得所有这些信息,这使得所有信息都可以立即运行。
您会注意到访问网络驱动器时速度变慢。这是因为它一次只检索一个级别,同时缓存结果并刷新其他访问权限。
最后,我认为你还有其他事情要发生。解析单个文件名的10ms有点极端。
答案 1 :(得分:2)
你访问时间很奇怪,我怀疑你真正的瓶颈在那里。例如,我刚刚运行了一个测试应用程序并得到了这个(注意:我有一个SSD,所以我的测试几乎消除了磁盘访问速度的影响):
Finding all files inside E:\ (recursive)...
Directory.GetFiles found 91731 files in 10,600 ms: 115.6 microseconds/file
Path.GetFileName parsed 91731 files in 134 ms: 1.5 microseconds/file
那是微秒。大部分时间都花在将文件提取到数组中,之后解析文件名是微不足道的。
最重要的是:我建议您下载一个分析器(如EQUATEC),并检查您的时间花在哪里。
如果你想自己尝试一下,这是我的代码:
class Program
{
static void Main(string[] args)
{
var stopwatch = new Stopwatch();
var path = @"E:\";
Console.WriteLine("Finding all files inside {0} (recursive)", path);
stopwatch.Restart();
var allFiles = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
stopwatch.Stop();
Output("Directory.GetFiles found", allFiles.Length, stopwatch.ElapsedMilliseconds);
stopwatch.Restart();
var filenames = allFiles.Select(Path.GetFileName).ToArray();
stopwatch.Stop();
Output("Path.GetFileName parsed", filenames.Length, stopwatch.ElapsedMilliseconds);
Console.Read();
}
private static void Output(string action, int len, long timeMs)
{
Console.WriteLine("{0} {1} files in {2:#,##0} ms: {3:0.0} microseconds/file", action, len, timeMs, timeMs * 1000.0 / len);
}
}