我的应用程序需要打开很多小文件,比如1440个文件,每个文件包含1分钟的数据,以读取某一天的所有数据。每个文件只有几个KB大。这是一个GUI应用程序,所以我希望用户(==我!)不必等待太长时间。
事实证明打开文件的速度相当慢。经过研究,大多数时间都浪费在为每个文件创建FileStream(OpenStream = new FileStream)。示例代码:
// stream en reader aanmaken
FileStream OpenStream;
BinaryReader bReader;
foreach (string file in files)
{
// bestaat de file? dan inlezen en opslaan
if (System.IO.File.Exists(file))
{
long Start = sw.ElapsedMilliseconds;
// file read only openen, anders kan de applicatie crashen
OpenStream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
Tijden.Add(sw.ElapsedMilliseconds - Start);
bReader = new BinaryReader(OpenStream);
// alles in één keer inlezen, werkt goed en snel
// -bijhouden of appenden nog wel mogelijk is, zonodig niet meer appenden
blAppend &= Bestanden.Add(file, bReader.ReadBytes((int)OpenStream.Length), blAppend);
// file sluiten
bReader.Close();
}
}
使用秒表计时器,我发现大多数(> 80%)的时间花在为每个文件创建FileStream上。创建BinaryReader并实际读取文件(Bestanden.add)几乎没有时间。
我对此感到困惑,无法找到加快速度的方法。我该怎么做才能加快FileStream的创建速度?
更新问题:
答案 0 :(得分:2)
正如您在问题的评论中提到的那样FileStream
通过创建对象将第一个4K读取缓冲区。您可以更改此缓冲区的大小以反映更好的数据大小。 (例如,如果文件小于缓冲区,则减少)。如果您按顺序读取文件,则可以通过FileOptions
向OS提供有关此内容的提示。此外,您可以避免使用BinaryReader
,因为您完全阅读了文件。
// stream en reader aanmaken
FileStream OpenStream;
foreach (string file in files)
{
// bestaat de file? dan inlezen en opslaan
if (System.IO.File.Exists(file))
{
long Start = sw.ElapsedMilliseconds;
// file read only openen, anders kan de applicatie crashen
OpenStream = new FileStream(
file,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite,
bufferSize: 2048, //2K for example
options: FileOptions.SequentialScan);
Tijden.Add(sw.ElapsedMilliseconds - Start);
var bufferLenght = (int)OpenStream.Length;
var buffer = new byte[bufferLenght];
OpenStream.Read(buffer, 0, bufferLenght);
// alles in één keer inlezen, werkt goed en snel
// -bijhouden of appenden nog wel mogelijk is, zonodig niet meer appenden
blAppend &= Bestanden.Add(file, buffer, blAppend);
}
}
我不知道Bestanden
对象的类型。但是,如果此对象具有从数组中读取的方法,则还可以为文件重用缓冲区。
//the buffer should be bigger than the biggest file to read
var bufferLenght = 8192;
var buffer = new byte[bufferLenght];
foreach (string file in files)
{
//skip
...
var fileLenght = (int)OpenStream.Length;
OpenStream.Read(buffer, 0, fileLenght);
blAppend &= Bestanden.Add(file, /*read bytes from buffer */, blAppend);
我希望它有所帮助。
答案 1 :(得分:0)
免责声明:这个答案只是一个(成熟的)推测,它是一个Windows bug,而不是你可以使用不同代码修复的东西。
因此,此行为可能与此处描述的Windows错误有关:"24-core CPU and I can’t move my mouse"。
这些进程都是从NtGdiCloseProcess中释放锁。
因此,如果FileStream
在操作系统中使用并保持这样一个关键锁定,那么它会等待几个μSecs用于每个文件,这将增加数千个文件。它可能是一个不同的锁,但上面提到的错误至少增加了类似问题的可能性。
为证明或反驳这一假设,有必要深入了解内核的内部工作原理。