2009-09-15 8 views
6

Ok, więc wyjaśnić; Pracuję dla systemu, który może znieść awarię zasilania w dowolnym momencie, jeden punkt, który testuję jest bezpośrednio po tym, jak napisałem plik za pomocą StreamWriter. Poniższy kod:Strata mocy po StreamWriter.Close() generuje pusty plik, dlaczego?

// Write the updated file back out to the Shell directory. 
using (StreamWriter shellConfigWriter = 
     new StreamWriter(@"D:\xxx\Shell\Config\Game.cfg.bak")) 
{ 
    for (int i = 0; i < configContents.Count; i++) 
    { 
     shellConfigWriter.WriteLine(configContents[i]); 
    } 
    shellConfigWriter.Close(); 
} 

FileInfo gameCfgBackup = new FileInfo(@"D:\xxx\Shell\Config\Game.cfg.bak"); 
gameCfgBackup.CopyTo(@"D:\xxx\Shell\Config\Game.cfg", true); 

Zapisuje zawartość shellConfigWriter (a List ciągów) do pliku używany jako tymczasowy sklep, to jest skopiowane z oryginałem. Po zakończeniu wykonywania tego kodu zasilanie zostanie utracone, po ponownym uruchomieniu ponownie plik Game.cfg istnieje i ma prawidłowy rozmiar, ale jest całkowicie pusty. Na początku pomyślałem, że jest to spowodowane włączeniem Write-Caching na dysku twardym, ale nawet po jej wyłączeniu nadal występuje (choć rzadziej).

Wszelkie pomysły byłyby bardzo mile widziane!

Aktualizacja: Ok, więc po usunięciu sprawozdania .Close() i nazywając .Flush() po każdej operacji zapisu plików nadal kończy się pusty. Mogę pójść o krok dalej i najpierw utworzyć kopię zapasową oryginalnego pliku, przed utworzeniem nowego, a następnie mam wystarczającą ilość kopii zapasowych, aby wykonać test integralności, ale nie sądzę, że pomoże to rozwiązać podstawowy problem (że kiedy każę mu pisać, opróżniać i zamykać plik ... To nie działa!).

+0

jest 'Game.cfg.bak' puste, jak również? –

+0

Tak, oba są puste. :( – Siyfion

+2

C# ma bufor, system operacyjny ma bufor lub dwa i twój dysk fizyczny ma bufor.Myślę, że możesz wpływać tylko na pierwsze dwa z C#. Zawsze będziesz tracić dane w sytuacji utraty zasilania, Pytanie brzmi: jak bardzo – Pod

Odpowiedz

11

Utrzymuj OS od buforowane wyjście używając parametru FileOptions z konstruktora FileStream obiektu:

using (Stream fs = new FileStream(@"D:\xxx\Shell\Config\Game.cfg.bak", FileMode.Create, FileAccess.Write, FileShare.None, 0x1000, FileOptions.WriteThrough)) 
    using (StreamWriter shellConfigWriter = new StreamWriter(fs)) 
    { 
     for (int i = 0; i < configContents.Count; i++) 
     { 
      shellConfigWriter.WriteLine(configContents[i]); 
     } 
     shellConfigWriter.Flush(); 
     shellConfigWriter.BaseStream.Flush(); 
    } 
+0

Fantastyczne! Great find;) – Siyfion

+1

Alternatywą dla "new FileStream" jest statyczna metoda File.Create: "File.Create (@" D: \ xxx \ Shell \ Config \ Game.cfg.bak ", 0x1000, FileOptions.WriteThrough, null) ". Ma kilka mniej parametrów i może wyglądać czysto w kodzie. –

6

Po pierwsze, nie trzeba tam dzwonić pod numer shellConfigWriter.Close(). Oświadczenie using zajmie się tym. Zamiast tego możesz chcieć ochronić się przed awarią zasilania pod numerem shellConfigWriter.Flush().


Aktualizacja
Coś jeszcze może warto rozważyć jest to, że w przypadku awarii zasilania może się wydarzyć w żadnego czas, to może się zdarzyć w środku zapisu, tak, że tylko niektóre z Bajty przechodzą do pliku. Naprawdę nie ma sposobu, aby to zatrzymać.

Aby zabezpieczyć się przed tymi scenariuszami, typową procedurą jest użycie plików flag stanu/warunku. Używasz istnienia lub nieistnienia w systemie plików z zerowym bajtem o konkretnej nazwie, aby poinformować program, gdzie można go ponownie odebrać po wznowieniu. Wtedy nie tworzysz ani nie niszczysz plików, które wyzwalają określony stan, dopóki nie osiągniesz tego stanu i nie ukończyłeś poprzedniej wersji.

Wadą jest to, że może to oznaczać, że od czasu do czasu rzuca się dużo pracy. Ale korzyścią jest to, że funkcjonalna część kodu wygląda normalnie: nie ma zbyt wiele dodatkowej pracy, aby system był wystarczająco solidny.

+0

Zgadzam się, nie miałem tam metody .Close() z tego konkretnego powodu, ale brakowało mi rzeczy do wypróbowania! Spróbuję spłukać po każdym napisaniu połączenia, zobacz co się stanie następnie. – Siyfion

+0

Bez powodzenia, nadal nie napisałem ani jednej linii. – Siyfion

0

Chcesz ustawić AutoFlush = true;

+0

Tak, mogłem, ale dla celów tego kodu przykładowego jest 1 linia w obie strony; przepłukać co do iteracji lub ustawić AutoFlush na true. Wciąż daje ten sam wynik, co oznacza, że ​​wciąż tworzy pusty plik. – Siyfion

+0

Czy na pewno nie piszesz tylko pustych linii do pliku? ; p – leppie