2012-10-22 18 views
12

Piszę rozwiązanie zapasowe (sort). Po prostu kopiuje plik z lokalizacji C: \ i wkleja go do lokalizacji Z: \Jak się dowiedzieć, czy plik został zmodyfikowany?

Aby zapewnić szybkość jest szybka, przed skopiowaniem i wklejeniem sprawdza, czy plik oryginalny istnieje. Jeśli tak, wykonuje kilka "obliczeń", aby sprawdzić, czy kopia powinna być kontynuowana lub czy plik kopii zapasowej jest aktualny. Właśnie te obliczenia są trudne.

Oryginalnie porównałem rozmiar pliku, ale nie jest to wystarczająco dobre, ponieważ byłoby bardzo możliwe, aby zmienić plik i mieć taki sam rozmiar (na przykład zapisanie znaku C w notatniku ma taki sam rozmiar, jak w przypadku uratował postać T).

Muszę się więc dowiedzieć, czy zmieniona data jest inna. W tej chwili otrzymuję informacje o pliku przy użyciu klasy FileInfo, ale po przejrzeniu wszystkich pól nie ma niczego, co wydaje się odpowiednie.

Jak mogę sprawdzić, czy kopiuję pliki, które zostały zmodyfikowane?

EDIT Widziałem sugestii na SO w użyciu sum kontrolnych MD5, ale jestem zaniepokojony to może być problem, ponieważ niektóre pliki Jestem porównujących będzie do 10GB

+2

Jest taki ładny atrybut meta, który ma większość systemów plików, ogólnie nazywany "czasem ostatniej modyfikacji". –

+0

Ale nie rozumiem tego z FileInfo - Zgadzam się, że jest to prawdopodobnie idealne, ale nie wiem, która klasa dostarczy mi tej informacji. – Dave

+1

FileInfo.LastWriteTime nie ma tych informacji? Takie wrażenie uzyskałem od tego pytania: http: //stackoverflow.com/questions/1185378/how-to-get-modified-date-from-file-in-c-sharp – JoshVarty

Odpowiedz

13

Przechodzenie przez daty modyfikacji będzie niewiarygodne - zegar komputer może przejść do tyłu podczas synchronizacji lub gdy regulować ręcznie. Niektóre programy mogą nie zachowywać się dobrze podczas modyfikowania lub kopiowania plików w zakresie zarządzania zmodyfikowaną datą.

Przechodzenie przez bit archiwum może działać w kontrolowanym środowisku, ale co się stanie, jeśli uruchomiona jest inna część oprogramowania, która używa również bitów archiwum?

The Windows archive bit is evil and must be stopped

Jeśli chcesz (prawie) pełna niezawodność, to co należy zrobić, to zapisać wartość hash ostatnią kopię zapasową wersję przy użyciu dobrej funkcję mieszającą jak SHA1, a jeżeli zmiany wartości hash następnie przesłać nowa kopia.

Oto klasa SHA1 wraz z próbką kodu na dole:

http://msdn.microsoft.com/en-us/library/system.security.cryptography.sha1.aspx

Wystarczy uruchomić bajty plików przez nią i przechowywania wartości hash. Przekaż mu numer FileStream zamiast ładować plik do pamięci za pomocą tablicy bajtów, aby zmniejszyć wykorzystanie pamięci, szczególnie w przypadku dużych plików.

Można połączyć to z modyfikowaną datą na różne sposoby, aby dostosować program do potrzebnych szybkości i niezawodności.Na przykład możesz sprawdzić zmodyfikowane daty większości kopii zapasowych i okresowo uruchamiać sprawdzanie skrótu, które działa, gdy system jest bezczynny, aby upewnić się, że nic nie zostało pominięte. Czasami zmieniona data ulegnie zmianie, ale zawartość pliku pozostanie taka sama (tzn. Zostanie nadpisana tymi samymi danymi), w takim przypadku można uniknąć ponownego wysłania całego pliku po ponownym obliczeniu wartości skrótu i ​​uświadomieniu sobie, że wciąż jest taka sama.

Większość systemów kontroli wersji używa pewnego rodzaju połączonego podejścia z hasłami i zmodyfikowanymi datami.

Twoje podejście wiąże się zazwyczaj z pewnym rodzajem zarządzania ryzykiem z kompromisem między wydajnością i niezawodnością, jeśli nie chcesz wykonywać pełnej kopii zapasowej i wysyłać wszystkich danych za każdym razem. Z tego powodu ważne jest, aby raz na jakiś czas wykonywać "pełne kopie zapasowe".

+0

Dla jasności, kiedy mówisz zapisać hash, czy ty w zewnętrznym pliku lub bazie danych (lub tym podobnych)? – Dave

+3

To zależy od tego, jak twój system jest zaimplementowany :) Możesz przechowywać bazę danych z wartościami lub możesz zrobić to, co zrobiła subversion i utworzyć ukryty katalog wewnątrz kopii zapasowej, zawierający skróty wszystkich plików, które zostały zabezpieczone w górę. Subversion odszedł od tego i teraz przechowuje bazę danych w ukrytym katalogu tylko w katalogu głównym wersji struktury katalogów. –

+0

Rozumiem - ale to polegałoby na przechowywaniu tych danych gdzie indziej - interesujące. Dziękuję za poświęcenie czasu i pomoc. – Dave

7

Może chcesz aby sprawdzić klasę FileSystemWatcher.

„Klasa ta pozwala monitorować katalog dla zmian i będzie ogień zdarzenie gdy coś jest modyfikowany.”

Twój kod może następnie obsługiwać zdarzenie i przetwarzać plik.

źródło Code - MSDN:

// Create a new FileSystemWatcher and set its properties. 
FileSystemWatcher watcher = new FileSystemWatcher(); 
watcher.Path = args[1]; 

/* Watch for changes in LastAccess and LastWrite times, and 
    the renaming of files or directories. */ 
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite 
    | NotifyFilters.FileName | NotifyFilters.DirectoryName; 

// Only watch text files. 
watcher.Filter = "*.txt"; 

// Add event handlers. 
watcher.Changed += new FileSystemEventHandler(OnChanged); 
watcher.Created += new FileSystemEventHandler(OnChanged); 
watcher.Deleted += new FileSystemEventHandler(OnChanged); 
watcher.Renamed += new RenamedEventHandler(OnRenamed); 
+1

Mój program nie jest przeznaczony do oglądania folderu 24/7, sprawdza tylko 2 pliki w locie (w momencie kopiowania/wklejania). Więc +1, ponieważ jest to dobra informacja i użyteczne jako alternatywa, ale ja chcę porównać 2 pliki. – Dave

+1

FYI, to nie wydaje się być zgodne z Mono. – joelc

10

można porównać pliki według ich skrótów:

private byte[] GetFileHash(string fileName) 
{ 
    HashAlgorithm sha1 = HashAlgorithm.Create(); 
    using(FileStream stream = new FileStream(fileName,FileMode.Open,FileAccess.Read)) 
     return sha1.ComputeHash(stream); 
} 

Jeśli treść została zmieniona, hashe będzie inna.

+0

+1 Dziękuję za kod. Wydaje się to bardzo proste i warto porównać 2 bajty na końcu. Dobra odpowiedź, dziękuję – Dave

+1

Nie wystarczy porównać tylko dwa ostatnie bajty. Użyj 'hash1.SequenceEqual (hash2)' do porównania wszystkich bajtów –

+0

2 bajty będące źródłem i miejscem docelowym – Dave

1

Ogólnie rzecz biorąc, pozwolisz systemowi OS zadbać o śledzenie, czy plik się zmienił, czy nie.

Jeśli używasz:

File.GetAttributes 

i sprawdzić, czy flaga archiwum, to będzie powiedzieć, czy plik został zmieniony od ostatniego archiwizowane. Wierzę, że XCOPY i podobne resetują tę flagę po wykonaniu kopii, ale być może trzeba będzie się tym zająć samodzielnie.

Można łatwo sprawdzić flagę w DOS przy użyciu:

dir /aa yourfilename 

Lub po prostu dodać kolumnie Atrybuty w Eksploratorze Windows.

1

Flaga archiwum plików jest zwykle używana przez programy kopii zapasowych w celu sprawdzenia, czy plik wymaga utworzenia kopii zapasowej. Gdy system Windows modyfikuje lub tworzy plik, ustawia flagę archiwum (patrz here). Sprawdź, czy flaga archiwum znajduje się zdecydować, czy potrzebuje pliku kopii zapasowej:

if ((File.GetAttributes(fileName) & FileAttributes.Archive) == FileAttributes.Archive) 
{ 
    // Archive file. 
} 

Po wykonaniu kopii zapasowej pliku, wyczyścić flagę archiwum:

File.SetAttributes(fileName, File.GetAttributes(fileName) & ~FileAttributes.Archive); 

ta zakłada żadnych innych programów (np System oprogramowanie do tworzenia kopii zapasowych) czyści flagę archiwum.

+0

To jest wspaniałe - dziękuję, bardzo dobrze wyjaśnione. – Dave

Powiązane problemy