2012-04-26 37 views
5

Tôi đang cố gắng thiết kế một ứng dụng đơn giản để được sử dụng để tính toán một tệp CRC32/md5/sha1/sha256/sha384/sha512 và tôi đã gặp phải một chút rào cản. Điều này đang được thực hiện trong C#.Làm thế nào để băm một tập tin duy nhất nhiều cách cùng một lúc?

Tôi muốn có thể thực hiện điều này một cách hiệu quả nhất có thể, vì vậy suy nghĩ ban đầu của tôi là đọc tệp vào bộ nhớ trước khi xử lý, nhưng tôi sớm phát hiện ra rằng các tệp rất lớn khiến tôi hết bộ nhớ rất nhanh. Vì vậy, có vẻ như tôi phải sử dụng một bộ phim để thay thế. Vấn đề, như tôi thấy, là chỉ có một hàm băm có thể chạy cùng một lúc và làm như vậy với một luồng phim sẽ mất một lúc để mỗi băm hoàn thành.

Làm cách nào để đọc một tệp nhỏ vào bộ nhớ, xử lý nó bằng tất cả 6 thuật toán, sau đó chuyển sang một đoạn khác ... Hoặc băm không hoạt động theo cách đó?

Đây là nỗ lực ban đầu của tôi khi đọc tệp vào bộ nhớ. Nó thất bại khi tôi đã cố gắng để đọc một tập tin ảnh CD vào bộ nhớ trước khi chạy các thuật toán băm trên MemoryStream: thuật toán

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

Trả lời

3

Bạn hầu hết ở đó, bạn không cần phải đọc toàn bộ nội dung vào bộ nhớ cùng một lúc.

Tất cả các băm trong .Net được lấy từ lớp HashAlgorithm. Điều này có hai phương pháp trên đó: TransformBlockTransformFinalBlock. Vì vậy, bạn sẽ có thể đọc một đoạn cho tập tin của bạn, công cụ nó vào phương pháp TransformBlock của băm nào bạn muốn sử dụng, và sau đó di chuyển vào khối tiếp theo. Chỉ cần nhớ gọi TransformFinalBlock cho đoạn cuối cùng của bạn từ tệp, vì đó là những gì giúp bạn mảng byte chứa hàm băm.

Còn bây giờ, tôi sẽ chỉ làm mỗi băm cùng một lúc, cho đến khi nó làm việc, sau đó lo lắng về việc chạy các băm đồng thời (sử dụng một cái gì đó giống như Thư viện Parallel Task)

+0

Tôi đã thử làm việc này bằng MD5 và chương trình chạy, mặc dù chương trình có vẻ như đang tạo băm không đúng. Đây là liên kết tới mã của tôi: [link] (http://pastebin.com/i3iPwYZv) – agent154

+1

Bạn nên sử dụng 'read' thay vì' buffer.Length' khi gọi 'TransformFinalBlock' –

+0

Cảm ơn rất nhiều! Tôi đã rất đau đớn về điều này trong một thời gian tối qua. Kết thúc với việc hack một thứ gì đó ngu ngốc đang tìm cách để nó hoạt động, nhưng tôi không thể không cảm thấy rằng nó không cần thiết. Tôi phát hiện ra rằng đó là vì mảng cuối cùng đã được đọc hoàn toàn ngay cả khi đoạn cuối cùng quá nhỏ cho nó. Tôi đã kết thúc làm cho nó tạo ra một mảng byte mới cho mảnh cuối cùng bằng kích thước của đoạn cuối cùng. – agent154

4

Hash được thiết kế theo cách mà bạn có thể tính giá trị băm từng bước. Bạn có thể tìm thấy ví dụ C# /. NET cho số here đó. Bạn có thể dễ dàng sửa đổi mã được cung cấp để cập nhật nhiều cá thể thuật toán băm trong mỗi bước.

0

Đây có thể là một cơ hội tuyệt vời để có được bàn chân của bạn ướt với các đối tượng dòng dữ liệu TPL. Đọc tệp trong một chuỗi và đăng dữ liệu lên BroadcastBlock<T>. BroadcastBlock<T> sẽ được liên kết với 6 trường hợp ActionBlock<T> khác nhau. Mỗi ActionBlock<T> sẽ tương ứng với một trong 6 chiến lược băm của bạn.

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> sẽ chuyển tiếp từng đoạn dữ liệu đến tất cả các trường hợp ActionBlock<T> được liên kết.

Vì câu hỏi của bạn tập trung nhiều hơn vào cách làm cho tất cả điều này xảy ra đồng thời, tôi sẽ để việc triển khai DoHash tùy thuộc vào bạn.

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

Điều này trông giống như một cách tiếp cận rất thú vị để đa luồng. Xấu hổ nó trong .net 4.5. Vì lý do gì đó, tôi có đủ thời gian để thuyết phục bản thân mình sử dụng .net 4.0, vì nó không cảm thấy đủ chính thống với tôi. – agent154

+0

Dường như phương pháp này sẽ không hoạt động. DoHash sẽ được gọi cho mỗi mảng đầu vào của byte. Họ nên kết hợp như thế nào? – Petro

Các vấn đề liên quan