2009-05-29 13 views
5

Czy można buforować plik binarny w .NET i wykonywać normalne operacje na plikach w pamięci podręcznej?Buforowanie pliku binarnego w języku C#

+2

Huh? Co masz na myśli przez 1) Pamięć podręczna? 2) Plik binarny (np. Plik tekstowy, plik wykonywalny, obraz)? 3) Operacje "Normalny plik"? –

+1

Również dlaczego chcesz go cache'ować? Może to jest niepotrzebne? – uriDium

+0

podaj proszę przypadek użycia. –

Odpowiedz

11

Aby to zrobić, należy przeczytać całą zawartość obiektu FileStream w obiekcie MemoryStream, a następnie użyć tego obiektu do operacji we/wy. Oba typy dziedziczą po Stream, więc użycie będzie skutecznie identyczne.

Oto przykład:

private MemoryStream cachedStream; 

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

Więc po prostu wywołać metodę CacheFile raz kiedy chcesz buforować dany plik, a następnie nigdzie indziej w użyciu kodu cachedStream do czytania. (Faktyczny plik zostanie zamknięty, gdy tylko jego zawartość zostanie zapisana w pamięci podręcznej.) Jedyną rzeczą do zapamiętania jest pozbycie się cachedStream, gdy skończysz.

+3

+1: Myślę, że to może być to, czego chce pytający. –

+0

Prawdopodobnie wszystko będzie dobrze - jedynym problemem będzie sytuacja, w której mówimy o pliku o wielkości GB lub dwóch. –

+2

Ta metoda oczywiście przestaje być przydatna, gdy rozmiar pliku zbliża się do rozmiaru pamięci RAM. W tym momencie powinieneś jednak używać serwera bazy danych, więc zakładam, że to nie będzie problemem. – Noldorin

3

Każdy nowoczesny system operacyjny ma wbudowany system buforowania, więc w rzeczywistości za każdym razem, gdy wchodzisz w interakcję z plikiem, wchodzisz w interakcję z pamięcią podręczną w pamięci tego pliku.

Przed zastosowaniem niestandardowego buforowania należy zadać ważne pytanie: co się dzieje, gdy plik bazowy ulegnie zmianie, więc moja kopia w pamięci podręcznej zostanie unieważniona?

Możesz dalej komplikować sprawy, jeśli kopia w pamięci podręcznej może się zmieniać, a zmiany muszą być zapisane z powrotem do pliku podstawowego.

Jeśli plik jest mały, prostszym rozwiązaniem jest użycie opcji MemoryStream, co sugeruje inna odpowiedź.

Jeśli chcesz zapisać zmiany z powrotem do pliku, możesz napisać klasę opakowania, która przekazuje wszystko dalej do MemoryStream, ale dodatkowo ma właściwość IsDirty, która ustawia wartość true, gdy wykonywana jest operacja zapisu. Następnie możesz mieć kod zarządzania, który uruchamia się w dowolnym momencie (pod koniec jakiejś większej transakcji?), Sprawdza, czy dla (IsDirty == true) i zapisuje nową wersję na dysku. Jest to nazywane buforowaniem "leniwym zapisem", ponieważ modyfikacje są dokonywane w pamięci i nie są zapisywane do pewnego czasu później.

Jeśli naprawdę chcesz komplikować sprawy lub masz bardzo duży plik, możesz zaimplementować własne stronicowanie, w którym wybierasz rozmiar bufora (może 1 MB?) I zachować niewielką liczbę stron o stałej liczbie stron, które zostały ustalone. rozmiar. Tym razem będziesz mieć brudną flagę dla każdej strony. Wdrożysz metody Stream, aby ukryć szczegóły od wywołującego i w razie potrzeby pobrać (lub odrzucić) bufory strony.

Wreszcie, jeśli chcesz łatwiejsze życie, spróbuj:

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

To pozwala wykorzystywać ten sam silnik SQL jak SQL Server, ale na pliku, ze wszystko dzieje się w procesie, a nie za pośrednictwem zewnętrzny serwer RDBMS. Zapewni to prawdopodobnie znacznie prostszy sposób sprawdzania i aktualizowania pliku oraz uniknięcia konieczności ręcznego pisania kodu trwałości.

+0

Czy to nie jest plik mapowany w pamięci (http://en.wikipedia.org/wiki/Memory-mapped_file)? Mimo to, zadzwonię do OP chce zamknąć uchwyt pliku tak szybko, jak to możliwe. – Noldorin

+0

Mapowanie pamięci to plik, w którym system operacyjny używa pliku (do wyboru) w celu zapewnienia magazynu pamięci wirtualnej dla regionu przestrzeni adresowej procesu. (Plik stronicowania służy temu celowi w przypadku zwykłej pamięci alokacji.) Mówię o tym, że system operacyjny ma buforowanie dysku, które działa niezależnie od tego, w jaki sposób uzyskujesz dostęp do pliku. Spróbuj użyć grep lub podobnego do przeszukiwania kilkuset MB plików tekstowych. Za drugim razem stanie się to znacznie szybciej, a twój dysk twardy nie wyda dźwięku, ponieważ wszystko jest w pamięci. –

+0

@Earwicker: Tak, jestem pewien, że masz rację. Niemniej jednak, kopiowanie zawartości do MemoryStream wydaje się być najlepszym rozwiązaniem, ponieważ a) nie utrzymuje blokady pliku b) Podejrzewam, że nadal będzie oferować wzrost wydajności. – Noldorin

3

Cóż, można oczywiście odczytać plik do tablicy byte [] i rozpocząć pracę nad nim. A jeśli chcesz używać strumienia można skopiować FileStream do MemoryStream i rozpocząć pracę z nim - jak:

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); 
     } 
} 

Jeśli chodzi o wydajność - dobrze, normalnie mechanizmy wbudowany w innym pliku metody dostępu powinny wystarczyć.

0

Nie wiem, co dokładnie robisz, ale oferują tę sugestię (które mogą lub nie mogą być opłacalne w zależności od tego, co robisz):

Zamiast tylko buforowanie zawartości katalogu plik, dlaczego nie umieścisz zawartości pliku w ładnie mocno wpisanej kolekcji przedmiotów, a następnie w pamięci podręcznej? Prawdopodobnie ułatwi to wyszukiwanie przedmiotów i przyspieszy, ponieważ nie ma potrzeby analizowania.

+0

plik zawiera wiele rekordów. w rzeczywistości jest to plik binarny bazy danych kraju maxmind –

+0

, z którego możemy przyjąć, że prawdziwym problemem jest to, że nie otrzymujesz wydajności, jaką chcesz od swoich zapytań? –

0

Istnieje bardzo elegancki system buforowania w Lucene, który buforuje bajty z dysku do pamięci i inteligentnie aktualizuje sklep itp. Możesz chcieć rzucić okiem na ten kod, aby zorientować się, jak to robią. Możesz również chcieć przeczytać na temat warstwy przechowywania danych Microsoft SQL Server - ponieważ zespół MSSQL jest dość otwarty na temat niektórych najważniejszych szczegółów implementacji.