2012-04-26 6 views
5

Próbuję zaprojektować prostą aplikację do obliczania pliku CRC32/md5/sha1/sha256/sha384/sha512, a ja natknąłem się na blokadę drogi. Robi się to w języku C#.Jak zaszyfrować jeden plik na wiele sposobów w tym samym czasie?

Chciałbym móc to zrobić tak skutecznie, jak to tylko możliwe, więc początkowo myślałem o wczytaniu pliku do pamięci memorystream przed przetworzeniem, ale szybko odkryłem, że bardzo duże pliki powodują, że brakuje mi pamięci bardzo szybko. Tak więc wydaje się, że zamiast tego muszę użyć strumienia pliku. Problemem, jak widzę, jest to, że tylko jedna funkcja skrótu może być uruchomiona w tym samym czasie, a zrobienie tego z strumieniem pliku zajmie trochę czasu, aby każdy hasz zakończył się.

W jaki sposób mogę przeczytać niewielką część pliku w pamięci, przetwarzając go przy użyciu wszystkich 6 algorytmów, a następnie przechodząc na inną porcję ... A może mieszanie nie działa w ten sposób?

To była moja oryginalna próba odczytania pliku do pamięci. Nie udało się, kiedy próbowałem odczytać obraz płyty do pamięci przed uruchomieniem mieszania algorytmy na MemoryStream: algorytmy

private void ReadToEndOfFile(string filename) 
    { 
     if (File.Exists(filename)) 
     { 
      FileInfo fi = new FileInfo(filename); 
      FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read); 
      byte[] buffer = new byte[16 * 1024]; 

      //double step = Math.Floor((double)fi.Length/(double)100); 

      this.toolStripStatusLabel1.Text = "Reading File..."; 
      this.toolStripProgressBar1.Maximum = (int)(fs.Length/buffer.Length); 
      this.toolStripProgressBar1.Value = 0; 

      using (MemoryStream ms = new MemoryStream()) 
      { 
       int read; 
       while ((read = fs.Read(buffer, 0, buffer.Length)) > 0) 
       { 
        ms.Write(buffer, 0, read); 
        this.toolStripProgressBar1.Value += 1; 
       } 

       _ms = ms; 
      } 
     } 
    } 

Odpowiedz

3

Jesteś na najlepszej drodze, po prostu nie musisz od razu czytać całej rzeczy w pamięci.

Wszystkie skróty w .Net pochodzą z klasy HashAlgorithm. Ma dwie metody: TransformBlock i TransformFinalBlock. Tak więc powinieneś być w stanie odczytywać fragment pliku, wciskać go w metodę TransformBlock, bez względu na to, jakie skróty chcesz użyć, a następnie przejść do następnego bloku. Pamiętaj tylko, aby wywołać TransformFinalBlock dla ostatniego kawałka z pliku, ponieważ to jest to, co dostajesz tablicę bajtów zawierającą hasz.

Na razie chciałbym tylko zrobić każdy hash jeden na raz, dopóki nie działa, wtedy martwić o mieszań jednocześnie (przy użyciu coś jak Parallel Library Task)

+0

Próbowałem uruchomić to przy użyciu MD5, a program działa, chociaż wydaje się generować nieprawidłowe hashe. Oto link do mojego kodu: [link] (http://pastebin.com/i3iPwYZv) – agent154

+1

Powinieneś używać 'read' zamiast' buffer.Length' podczas wywoływania 'TransformFinalBlock' –

+0

Wielkie dzięki! Przez ostatnią noc męczyłem się nad tym. Skończyło się na hakowaniu czegoś, co głupio wyglądało, żeby to zadziałało, ale nie mogłem przestać myśleć, że to było niepotrzebne. Dowiedziałem się, że to dlatego, że ostatnia tablica była w pełni czytana, nawet jeśli ostatnia porcja była za mała. W końcu udało mi się stworzyć nową tablicę bajtów dla ostatniego elementu, która równa się wielkości ostatniego fragmentu. – agent154

4

Hash są zaprojektowane w taki sposób, że można obliczyć wartość skrótu stopniowo. Możesz znaleźć przykład C#/.NET dla tego here. Można łatwo zmodyfikować dostarczony kod, aby zaktualizować wiele instancji algorytmu mieszania w każdym kroku.

0

To może być doskonała okazja, aby uzyskać twoje stopy są mokre dzięki obiektom przepływu danych TPL. Przeczytaj plik w jednym wątku i opublikuj dane w pliku BroadcastBlock<T>. Obiekt BroadcastBlock<T> zostanie powiązany z 6 różnymi instancjami ActionBlock<T>. Każdy ActionBlock<T> będzie odpowiadał jednej z twoich 6 strategii mieszania.

var broadcast = new BroadcastBlock<byte[]>(x => x); 

var strategy1 = new ActionBlock<byte[]>(input => DoHash(input, SHA1.Create())); 
var strategy2 = new ActionBlock<byte[]>(input => DoHash(input, MD5.Create())); 
// Create the other 4 strategies. 

broadcast.LinkTo(strategy1); 
broadcast.LinkTo(strategy2); 
// Link the other 4. 

using (var fs = File.Open(@"yourfile.txt", FileMode.Open, FileAccess.Read)) 
using (var br = new BinaryReader(fs)) 
{ 
    while (br.PeekChar() != -1) 
    { 
    broadcast.Post(br.ReadBytes(1024 * 16)); 
    } 
} 

BroadcastBlock<T> przekaże każdą porcję danych do wszystkich połączonych ActionBlock<T> przypadkach.

Ponieważ twoje pytanie skupiało się bardziej na tym, jak doprowadzić do tego, aby wszystkie pojawiały się jednocześnie, zostawię implementację DoHash.

private void DoHash(byte[] input, HashAlgorithm algorithm) 
{ 
    // You will need to implement this. 
} 
+0

To wygląda na bardzo interesujące podejście do wielowątkowości. Szkoda, że ​​jest w .net 4.5. Z jakiegoś powodu, mam wystarczająco dużo czasu, by przekonać się do korzystania z .net 4.0, ponieważ nie jest to dla mnie wystarczająco popularne. – agent154

+0

Wygląda na to, że to podejście nie zadziała. DoHash zostanie wywołany dla każdej wejściowej tablicy bajtów. Jak powinny być łączone? – Petro

Powiązane problemy