计算文件Hash(SHA1、MD5等)

HashAlgorithm类支持数据块的Hash运算:对数据前面块通过TransformBlock方法计算,最后一块通过TransformFinalBlock方法计算,结果通过Hash属性获得,便可完成整个Hash过程。对于一个数据流(如文件流),可以利用这个办法,提供Hash的计算进度。下面是一个不带计算进度的使用的使用TransformBlock方式的代码。

 

using System;
using System.IO;
using System.Security.Cryptography;

namespace SHA1_and_MD5
{
    public static class Algorithm
    {
        /// <summary>
        /// 计算文件的Hash值
        /// </summary>
        /// <param name="fileName">文件名</param>
        /// <param name="hashName">Hash名</param>
        /// <returns>Hash的文本结果</returns>
        public static string ComputeHash(string fileName, string hashName)
        {
            var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
            var value = Hash(fs, hashName);
            fs.Close();
            return BitConverter.ToString(value).Replace("-", "").ToLower();
        }

        /// <summary>
        /// 计算流的Hash值
        /// </summary>
        /// <param name="stream">流</param>
        /// <param name="hashName">Hash名</param>
        /// <returns>Hash结果</returns>
        public static byte[] ComputeHash(Stream stream, string hashName)
        {
            const int bufferSize = 4096; //0x1000
            var hash = HashAlgorithm.Create(hashName);
            int num;
            var buffer = new byte[bufferSize];
            do
            {
                num = stream.Read(buffer, 0, bufferSize);
                if (num == bufferSize)
                {
                    hash.TransformBlock(buffer, 0, num, buffer, 0);
                }
                else if (stream.Length == stream.Position)
                {
                    hash.TransformFinalBlock(buffer, 0, num);
                }
				else if (num > 0)
				{
					//当 0 < num < bufferSize 的情况
					var buffer2 = new byte[num];
					Buffer.BlockCopy(buffer, 0, buffer2, 0, num);
					hash.TransformBlock(buffer2, 0, num, buffer2, 0);
				}
            } while (num > 0);
            return hash.Hash;
        }
    }
}

 

代码中hashName参数可以为以下值:

hashName参考:http://msdn.microsoft.com/zh-cn/library/wet69s13(VS.90).aspx
  
简单名称 算法实现
SHA SHA1CryptoServiceProvider
SHA1 SHA1CryptoServiceProvider
System.Security.Cryptography.SHA1 SHA1CryptoServiceProvider
System.Security.Cryptography.HashAlgorithm SHA1CryptoServiceProvider
MD5 MD5CryptoServiceProvider
System.Security.Cryptography.MD5 MD5CryptoServiceProvider
SHA256 SHA256Managed
SHA-256 SHA256Managed
System.Security.Cryptography.SHA256 SHA256Managed
SHA384 SHA384Managed
SHA-384 SHA384Managed
System.Security.Cryptography.SHA384 SHA384Managed
SHA512 SHA512Managed
SHA-512 SHA512Managed
System.Security.Cryptography.SHA512 SHA512Managed
  

比如,想计算系统记事本的sha1和md5,可以这样调用:

 

接下来,对上面的代码进行修改,加入计算时回调HashingCallback和结束时回调EndCallback,在进行ComputeHash计算时,do-while中每处理完成一组数据,执行一次HashingCallback的回调函数,全部计算完成后执行EndCallback的回调函数。为了在计算过程中取消计算,增加Stop方法,它将_cancel字段设置为true,而ComputeHash方法的do-while条件增加对_cancel的判断。回调函数的参数都包含了一个可传递的object类型的State属性,HashingCallback委托的HashingState参数,目的给出计算Hash的进度,EndCallback的EndState属性,目的通知计算结束,给出是否为中途取消而结束的。而最后的Hash结果通过Hash属性获得。另外,重载ToString方法,直接输出字符串的Hash结果。

 

于是,我们的代码改写成可实例化的类:

using System;
using System.IO;
using System.Security.Cryptography;

namespace SHA1_and_MD5
{
    public class MyHashAlgorithm
    {
        #region Delegates

        /// <summary>
        /// 完成Hash计算的回调
        /// </summary>
        public delegate void EndCallback(EndState endState);

        /// <summary>
        /// 进行Hash计算时的回调
        /// </summary>
        public delegate void HashingCallback(HashingState hashingState);

        #endregion

        private bool _cancel; //取消计算

        /// <summary>
        /// 获得Hash结果
        /// </summary>
        public byte[] Hash { get; private set; }

        /// <summary>
        /// 输出Hash结果的字符串版本
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return Hash != null ? BitConverter.ToString(Hash).Replace("-", "").ToLower() : "";
        }

        /// <summary>
        /// 停止计算
        /// </summary>
        public void Stop()
        {
            _cancel = true;
        }

        /// <summary>
        /// 计算文件的Hash值
        /// </summary>
        /// <param name="fileName">文件名</param>
        /// <param name="hashName">Hash名</param>
        /// <param name="hashingCallback">进度回调函数</param>
        /// <param name="endCallback">结束计算的回调函数</param>
        /// <param name="state">传递给回调的参数</param>
        public void ComputeHash(string fileName, string hashName, HashingCallback hashingCallback,
                                EndCallback endCallback, object state)
        {
            using(var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                ComputeHash(fs, hashName, hashingCallback, endCallback, state);
            }
        }

        /// <summary>
        /// 计算流的Hash值
        /// </summary>
        /// <param name="stream">流</param>
        /// <param name="hashName">Hash名</param>
        /// <param name="hashingCallback">进度回调函数</param>
        /// <param name="endCallback">结束计算的回调函数</param>
        /// <param name="state">传递给回调的参数</param>
        public void ComputeHash(Stream stream, string hashName, HashingCallback hashingCallback, EndCallback endCallback,
                                object state)
        {
            const int bufferSize = 4096; //0x1000
            Hash = null;
            _cancel = false;

            bool nullHashingCallback = hashingCallback == null; //未指定计算时的回调
            long bytesRead = 0L; //已经完成的数据
            long totalBytesLength = stream.Length;

            HashAlgorithm hash = HashAlgorithm.Create(hashName);
            int num;
            var buffer = new byte[bufferSize];
            do
            {
                num = stream.Read(buffer, 0, bufferSize);
                if (num == bufferSize)
                {
                    hash.TransformBlock(buffer, 0, num, buffer, 0);
                }
                else if (totalBytesLength == stream.Position)
                {
                    hash.TransformFinalBlock(buffer, 0, num);
                }
				else if (num > 0)
				{
					var buffer2 = new byte[num];
					Buffer.BlockCopy(buffer, 0, buffer2, 0, num);
					hash.TransformBlock(buffer2, 0, num, buffer2, 0);
				}
                if (num <= 0 || nullHashingCallback) continue;
                bytesRead += num;
                hashingCallback(new HashingState(bytesRead, totalBytesLength, state)); //执行计算时回调
            } while (num > 0 && !_cancel);

            Hash = _cancel ? new byte[0] : hash.Hash; //获得计算结果
            if (endCallback != null) endCallback(new EndState(_cancel, state)); //执行结束回调
        }

        #region Nested type: EndState

        /// <summary>
        /// 为EndCallback提供数据
        /// </summary>
        public class EndState
        {
            internal EndState(bool isCancel, object state)
            {
                IsCancel = isCancel;
                State = state;
            }

            /// <summary>
            /// 是否取消退出的
            /// </summary>
            public bool IsCancel { get; private set; }

            /// <summary>
            /// 获得传递的参数
            /// </summary>
            public object State { get; private set; }
        }

        #endregion

        #region Nested type: HashingState

        /// <summary>
        /// 为HashingCallback提供数据
        /// </summary>
        public class HashingState
        {
            internal HashingState(long byteRead, long totalBytesLength, object state)
            {
                BytesRead = byteRead;
                TotalBytesLength = totalBytesLength;
                State = state;
            }

            /// <summary>
            /// 获得已经计算完成的字节数
            /// </summary>
            public long BytesRead { get; private set; }

            /// <summary>
            /// 获得总字节数
            /// </summary>
            public long TotalBytesLength { get; private set; }

            /// <summary>
            /// 获得传递的参数
            /// </summary>
            public object State { get; private set; }
        }

        #endregion
    }
}


 

为了实现多线程支持,在调用时请使用Thread类实现。

 

 --

感谢uking09检查代码中的BUG。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值