2009-05-29 24 views
5

Ist es möglich, eine Binärdatei in .NET zwischenzuspeichern und normale Dateioperationen in zwischengespeicherten Dateien auszuführen?Caching einer Binärdatei in C#

+2

Huh? Was meinst du mit 1) Cache? 2) Binärdatei (z. B. keine Textdatei, ausführbare Datei, Bild)? 3) "normale Datei" Operationen? –

+1

Auch warum möchten Sie es zwischenspeichern? Vielleicht ist es unnötig? – uriDium

+0

geben Sie bitte den Anwendungsfall an. –

Antwort

11

Der Weg, dies zu tun ist, den gesamten Inhalt von FileStream in ein MemoryStream Objekt zu lesen, und dieses Objekt später für I/O zu verwenden. Beide Typen erben von Stream, so dass die Verwendung effektiv identisch ist.

Hier ist ein Beispiel:

private MemoryStream cachedStream; 

public void CacheFile(string fileName) 
{ 
    cachedStream = new MemoryStream(File.ReadAllBytes(fileName)); 
} 

So rufen Sie die CacheFile Methode einmal, wenn Sie die angegebene Datei gecached werden sollen, und anderswo dann in Code verwenden cachedStream zum Lesen. (Die aktuelle Datei wird geschlossen, sobald der Inhalt zwischengespeichert wurde.) Es ist nur zu beachten, dass Sie die Datei cachedStream ablegen müssen, wenn Sie damit fertig sind.

+3

+1: Ich denke, das könnte tatsächlich sein, was der Fragesteller will. –

+0

Es wird wahrscheinlich gut gehen - das einzige Problem wäre, wenn wir über eine Datei sprechen, die eine Größe von ein oder zwei GB hat. –

+2

Ja, diese Methode hört natürlich auf, nützlich zu sein, wenn sich die Datei an die des RAM annähert. Zu diesem Zeitpunkt sollten Sie jedoch einen Datenbankserver verwenden, daher nehme ich an, dass dies hier kein Problem darstellt. – Noldorin

3

In jedem modernen Betriebssystem ist ein Caching-System integriert. Wenn Sie also mit einer Datei interagieren, interagieren Sie mit einem speicherinternen Cache der Datei.

Bevor Sie das benutzerdefinierte Caching anwenden, müssen Sie eine wichtige Frage stellen: Was passiert, wenn sich die zugrunde liegende Datei ändert, sodass meine zwischengespeicherte Kopie ungültig wird?

Sie können die Angelegenheit noch komplizierter machen, wenn die zwischengespeicherte Kopie sich ändern darf und die Änderungen in der zugrunde liegenden Datei gespeichert werden müssen.

Wenn die Datei klein ist, ist es einfacher, einfach MemoryStream zu verwenden, wie in einer anderen Antwort vorgeschlagen.

Wenn Sie Änderungen in der Datei speichern müssen, können Sie eine Wrapper-Klasse schreiben, die alles an MemoryStream weiterleitet, aber zusätzlich eine IsDirty-Eigenschaft besitzt, die bei jedem Schreibvorgang auf True gesetzt wird. Dann können Sie einen Verwaltungscode haben, der immer dann einsetzt, wenn Sie wählen (am Ende einer größeren Transaktion?), Auf (IsDirty == true) prüft und die neue Version auf Festplatte speichert. Dies wird als "Lazy Write" Caching bezeichnet, da die Änderungen im Speicher vorgenommen werden und erst später gespeichert werden.

Wenn Sie wirklich Dinge komplizieren wollen, oder Sie eine sehr große Datei haben, könnten Sie Ihren eigenen Paging implementieren, wo Sie eine Puffergröße (vielleicht 1 MB?) Auswählen und eine kleine Anzahl von byte[] Seiten davon festhalten Größe. Diesmal hättest du eine schmutzige Flagge für jede Seite. Sie würden die Stream-Methoden implementieren, damit sie die Details des Aufrufers verbergen und Seitenpuffer bei Bedarf ziehen (oder verwerfen).

Schließlich, wenn Sie ein leichteres Leben wollen, versuchen Sie:

http://www.microsoft.com/Sqlserver/2005/en/us/compact.aspx

Damit können Sie die gleiche SQL-Engine wie SQL Server verwenden, aber auf eine Datei, mit allem, was in Ihrem Prozess geschieht anstatt über ein externer RDBMS-Server. Dies wird Ihnen wahrscheinlich eine viel einfachere Möglichkeit geben, Ihre Datei abzufragen und zu aktualisieren und die Notwendigkeit für viel handgeschriebenen Persistenz-Code zu vermeiden.

+0

Ist das nicht eine Memory-Mapped-Datei (http://en.wikipedia.org/wiki/Memory-maped_file)? Trotzdem, ich schnorre das OP will den Dateigriff so schnell wie möglich schließen. – Noldorin

+0

Memory-Mapping einer Datei ist, wo das Betriebssystem eine Datei (Ihrer Wahl) verwendet, um den virtuellen Speicher-Backing-Speicher für eine Region des Adressraums des Prozesses bereitzustellen. (Die Auslagerungsdatei dient diesem Zweck für den normalen Zuweisungsspeicher.) Ich spreche über die Tatsache, dass das Betriebssystem über ein Festplatten-Caching verfügt, das unabhängig davon funktioniert, wie Sie auf die Datei zugreifen. Versuchen Sie es mit grep oder ähnlichem, um ein paar hundert MB Textdateien zu durchsuchen. Das zweite Mal, wenn Sie es tun, wird es viel schneller passieren und Ihre Festplatte wird keinen Ton machen, weil es alles im Speicher ist. –

+0

@Earwicker: Ja, ich bin sicher, du hast Recht. Nichtsdestotrotz scheint das Kopieren der Inhalte in einen MemoryStream die beste Lösung hier zu sein, weil a) es keine Sperre für die Datei aufrechterhält b) Ich vermute, dass es immer noch Leistungssteigerungen bietet. – Noldorin

3

Nun, Sie können natürlich die Datei in ein byte [] Array lesen und anfangen, daran zu arbeiten. Und wenn Sie möchten, einen Stream nutzen Sie Ihre Filestream in einen Memorystream kopieren und starten Sie mit ihm arbeiten - wie:

public static void CopyStream(Stream input, Stream output) 
{ 
     var buffer = new byte[32768]; 
     int readBytes; 
     while((readBytes = input.Read(buffer, 0, buffer.Length)) > 0) 
     { 
       output.Write(buffer, 0, readBytes); 
     } 
} 

Wenn Sie über die Leistung angeht - na ja, normalerweise die Build-in Mechanismen der verschiedenen Datei Zugriffsmethoden sollten ausreichen.

0

Ich weiß nicht, was genau Sie tun, aber ich biete diesen Vorschlag (die kann oder auch nicht durchführbar sein, je nachdem, was Sie tun):

Statt nur den Inhalt des Cachen Datei, warum legen Sie den Inhalt der Datei nicht in eine nette, stark typisierte Sammlung von Elementen und cachen Sie diese dann zwischen? Es wird wahrscheinlich die Suche nach Elementen ein bisschen einfacher und schneller machen, da kein Parsing involviert ist.

+0

Datei enthält viele Datensätze. es ist tatsächlich maxmind Land Datenbank Binärdatei –

+0

von dem können wir davon ausgehen, dass das eigentliche Problem ist, dass Sie nicht die Leistung erhalten, die Sie von Ihren Abfragen möchten? –

0

Es gibt ein sehr elegantes Caching-System in Lucene, das Bytes von der Festplatte in den Speicher zwischenspeichert und den Speicher intelligent aktualisiert. Sie könnten sich diesen Code ansehen, um sich ein Bild davon zu machen. Vielleicht möchten Sie auch auf der Microsoft SQL Server-Datenspeicherschicht nachlesen - da das MSSQL-Team einige der wichtigeren Implementierungsdetails sehr ausführlich behandelt.