/// <summary> /// Simple linear hashing for a file, the stream reads and hashes forward for each byte chunk; fast disks with fast CPUs might not notice difference between this and producer/consumer /// </summary> /// <param name="fileName">File to calculate hash for</param> /// <returns>Hash calculated for this file in format XX-XX-XX-XX</returns> private string _HashFile(string fileName) { var adler = new Adler32Managed(); string retval = string.Empty; using (FileStream stream = new FileStream(fileName, FileMode.Open)) { // Read bytes from stream and interpret them as ints byte[] buffer = new byte[BUFFER_SIZE]; int count = 0; // Read from the IO stream fewer times. while ((count = stream.Read(buffer, 0, buffer.Length)) > 0) { if (count == BUFFER_SIZE) adler.TransformBlock(buffer, 0, buffer.Length, buffer, 0); else adler.TransformFinalBlock(buffer, 0, buffer.Length); } } return BitConverter.ToString(adler.Hash); }
/// <summary> /// Producer/consumer style of hasher, optimized for longer files and non-blocking with threads; consult TPL for .NET 4.5 /// </summary> /// <param name="fileName">File to calculate hash for</param> /// <returns>Hash calculated for this file in format XX-XX-XX-XX</returns> private string _HashFileAsync(string fileName) { var adler = new Adler32Managed(); string retval = string.Empty; // A bounded collection. Increase, decrease, or remove the // maximum capacity argument to see how it impacts behavior. BlockingCollection<List<byte>> bufferBlocks = new BlockingCollection<List<byte>>(1024); // A simple blocking consumer with no cancellation. Task consumer = Task.Run(() => { List<byte> byteBuffer = null; while (!bufferBlocks.IsCompleted) { try { int offset = 0; byteBuffer = bufferBlocks.Take(); byte[] buffer = byteBuffer.ToArray(); if (!bufferBlocks.IsAddingCompleted || bufferBlocks.Count != 0) offset += adler.TransformBlock(buffer, 0, buffer.Length, buffer, 0); else adler.TransformFinalBlock(buffer, 0, buffer.Length); } catch (InvalidOperationException) { //Console.WriteLine("Adding was completed!"); break; } //Console.WriteLine("Take:{0} ", bufferBlocks.Count); } }); // A simple blocking producer with no cancellation. Task producer = Task.Run(() => { using (FileStream stream = new FileStream(fileName, FileMode.Open)) { // Read bytes from stream and interpret them as ints byte[] buffer = new byte[BUFFER_SIZE]; int count = 0; // Read from the IO stream fewer times. while ((count = stream.Read(buffer, 0, buffer.Length)) > 0) { bufferBlocks.Add(buffer.ToList()); //Console.WriteLine("Add:{0} Count={1}", buffer.LongLength, bufferBlocks.Count); } } // See documentation for this method. bufferBlocks.CompleteAdding(); }); Task.WaitAll(new Task[] { producer, consumer }); return BitConverter.ToString(adler.Hash); }