Ich bin auf eine Situation gestoßen, in der ich eine ziemlich große Datei habe, von der ich binäre Daten lesen muss.Schneller (unsicherer) BinaryReader in .NET
Folglich erkannte ich, dass die binäre Standardreader Implementierung in .NET ziemlich langsam ist. Beim Blick auf sie mit .NET Reflector stieß ich auf diese:
public virtual int ReadInt32()
{
if (this.m_isMemoryStream)
{
MemoryStream stream = this.m_stream as MemoryStream;
return stream.InternalReadInt32();
}
this.FillBuffer(4);
return (((this.m_buffer[0] | (this.m_buffer[1] << 8)) | (this.m_buffer[2] << 0x10)) | (this.m_buffer[3] << 0x18));
}
Was mich als äußerst ineffizient schlägt, denken, wie Computer wurden entwickelt, um mit 32-Bit-Werten zu arbeiten, da die 32-Bit-CPU erfunden wurde.
Also machte ich meine eigene (unsicher) FastBinaryReader Klasse mit Code wie diese statt:
public unsafe class FastBinaryReader :IDisposable
{
private static byte[] buffer = new byte[50];
//private Stream baseStream;
public Stream BaseStream { get; private set; }
public FastBinaryReader(Stream input)
{
BaseStream = input;
}
public int ReadInt32()
{
BaseStream.Read(buffer, 0, 4);
fixed (byte* numRef = &(buffer[0]))
{
return *(((int*)numRef));
}
}
...
}
die viel schneller ist - ich schaffte es 5-7 Sekunden hinter der Zeit zu rasieren es zu lesen, nahm 500 MB-Datei, aber es ist immer noch ziemlich langsam insgesamt (29 Sekunden zunächst und ~ 22 Sekunden jetzt mit meiner FastBinaryReader
).
Es verwirrt mich immer noch, warum es immer noch so lange dauert, so eine relativ kleine Datei zu lesen. Wenn ich die Datei von einem Datenträger auf einen anderen kopiere, dauert es nur ein paar Sekunden, so dass der Datenträgerdurchsatz kein Problem darstellt.
ich inlined weiter die ReadInt32 usw. Anrufe, und ich endete mit diesem Code auf:
using (var br = new FastBinaryReader(new FileStream(cacheFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, 0x10000, FileOptions.SequentialScan)))
while (br.BaseStream.Position < br.BaseStream.Length)
{
var doc = DocumentData.Deserialize(br);
docData[doc.InternalId] = doc;
}
}
public static DocumentData Deserialize(FastBinaryReader reader)
{
byte[] buffer = new byte[4 + 4 + 8 + 4 + 4 + 1 + 4];
reader.BaseStream.Read(buffer, 0, buffer.Length);
DocumentData data = new DocumentData();
fixed (byte* numRef = &(buffer[0]))
{
data.InternalId = *((int*)&(numRef[0]));
data.b = *((int*)&(numRef[4]));
data.c = *((long*)&(numRef[8]));
data.d = *((float*)&(numRef[16]));
data.e = *((float*)&(numRef[20]));
data.f = numRef[24];
data.g = *((int*)&(numRef[25]));
}
return data;
}
weitere Ideen, wie dies noch schneller zu machen? Ich dachte, vielleicht könnte ich Marshalling verwenden, um die gesamte Datei direkt in den Speicher über einer benutzerdefinierten Struktur abzubilden, da die Daten linear, fest und sequentiell sind.
Gelöst: Ich kam zu dem Schluss, dass FileStream Puffer/BufferedStream fehlerhaft sind. Bitte beachten Sie die akzeptierte Antwort und meine eigene Antwort (mit der Lösung) unten.
Es kann hilfreich sein: http://stackoverflow.com/questions/19558435/what-is-the-best-buffer-size-when-using-binaryreader-to-read-big-files-1gb/19837238? noredirect = 1 # 19837238 –