【发布时间】:2013-01-25 15:27:24
【问题描述】:
代码:
static void MultipleFilesToSingleFile(string dirPath, string filePattern, string destFile)
{
string[] fileAry = Directory.GetFiles(dirPath, filePattern);
Console.WriteLine("Total File Count : " + fileAry.Length);
using (TextWriter tw = new StreamWriter(destFile, true))
{
foreach (string filePath in fileAry)
{
using (TextReader tr = new StreamReader(filePath))
{
tw.WriteLine(tr.ReadToEnd());
tr.Close();
tr.Dispose();
}
Console.WriteLine("File Processed : " + filePath);
}
tw.Close();
tw.Dispose();
}
}
我需要对其进行优化,因为它非常慢:45 个平均大小为 40 - 50 Mb XML 文件的文件需要 3 分钟。
请注意:平均 45 MB 的 45 个文件只是一个示例,它可以是 n 大小为 m 的文件数,其中 n 以千为单位,m 平均为 128 Kb .简而言之,它可能会有所不同。
您能否提供一些关于优化的意见?
【问题讨论】:
-
45 个文件,每个文件平均 45MB,总共刚好超过 2GB。你预计这需要多长时间?磁盘 I/O 将占用大量时间。
-
调用
Dispose是多余的,因为您要处理的对象已经在 using 块中(它将为您处理 Dispose)。 -
您正在将每个文件加载到内存中。这么大的字符串会进入大对象堆,为什么不读取较小的数据块(重用缓冲区)?由于 using 语句,关闭/处置是无用的。原始流就足够了,因为您不处理/更改任何编码。完成所有这些之后……您会看到性能不会有太大变化,因为可能大部分时间都花在了 I/O 上。如果输出文件与输入文件不在同一个磁盘上,那么您甚至可以尝试异步读写(在写入时预读下一个文件/块)。
-
@Pratik 最后一点:如果您可能有 1000 多个文件,您可以考虑使用 Directory.EnumerateFiles 而不是 Directory.GetFiles。出于同样的原因,我建议您检查文件大小以确定哪种复制方法更好(一次大读取或多个小块)。最后不要使用 helper 函数 AppendAllText:它会在每次写入时打开和关闭文件。
-
@Pratik 不,大部分时间都花在(慢速)磁盘 I/O 上,使用不安全代码不会有任何收获。最好只重构代码以不浪费内存/CPU 并改进算法(好吧,即使 I/O 的多线程在某种程度上也是经验性的)。好吧,您可能会考虑重写您的代码以使用 ReadFileScatter 和 WriteFileGather 但坦率地说,我不知道您将获得多少性能提升(与使用它们相比,至少在非常高速的 SSD 足够普遍之前)。