c# hashcode compare file content (hash码比对文件内容)

1、使用System.security.Cryptography.HashAlgorithm类为每个文件生成一个哈希码,然后比较两个哈希码是否一致。    

2、 在比较文件内容的时候可以采用好几种方法。例如,检查文件的某一特定部分是否一致;如果愿意,你甚至可以逐字节读取文件,逐字节进行比较。这两种方法都是可以的,但在某些情况下,还是使用哈希码算法更为方便。
 
哈希算法将任意长度的二进制值映射为固定长度的较小二进制值,这个小的二进制值称为哈希值。该算法为一个文件生成一个小的(通常约为20字节)二进制“指纹”(binary fingerprint)。从统计学角度看,不同的文件不可能生成相同的哈希码。事实上,即使是一个很小的改动(比如,修改了源文件中的一个bit),也会有50%的几率来改变哈希码中的每一个bit。因此,哈希码常常用于数据安全方面。要生成一个哈希码,你必须首先创建一个HashAlgorithm对象,而这通常是调用HashAlgorithm.Create方法来完成的;然后调用HashAlgorithm.ComputeHash方法,它会返回一个存储哈希码的字节数组。
 
如何获取文件的基本信息:
 可以使用FileInfo类的相关属性
FileInfo.Exists:获取指定文件是否存在;
FileInfo.Name,FileInfo.Extensioin:获取文件的名称和扩展名;
FileInfo.FullName:获取文件的全限定名称(完整路径); 
FileInfo.Directory:获取文件所在目录,返回类型为DirectoryInfo; 
FileInfo.DirectoryName:获取文件所在目录的路径(完整路径);
FileInfo.Length:获取文件的大小(字节数)
FileInfo.IsReadOnly:获取文件是否只读;
FileInfo.Attributes:获取或设置指定文件的属性,返回类型为FileAttributes枚举,可以是多个值的组合;
FileInfo.CreationTime、FileInfo.LastAccessTime、FileInfo.LastWriteTime:分别用于获取文件的创建时间、访问时间、修改时间;  
 
利用哈希值判断两个文件内容是否相同  代码如下:
//获取文件hashcode信息 
public static Tuple<int,string> GetFileHashCodeInfo(Stream stream)
        {
            if (stream == null || stream.Length == 0)
                return new Tuple<int, string>(0, "");
            var hash = System.Security.Cryptography.HashAlgorithm.Create();
            //hash算法一般是返回20个元素的数组
            byte[] hashByte = hash.ComputeHash(stream);
            //这里用一个元组的目的是字符串比对耗时,可先通过hashByte相加或者增量相加(取倍数,取平方和,取序号倍乘等)比较,相等再比较hashcode字符串
            return new Tuple<int, string>(hashByte.Select(q => (int)q).Sum(),BitConverter.ToString(hashByte));
        }

public static void CompareFile()
        {
            string p_1 = @"E:\readme_1.txt";
            string p_2 = @"E:\readme_2.txt";

            var stream_1 = new System.IO.FileStream(p_1, System.IO.FileMode.Open);
            var hash_1=GetFileHashCodeInfo(stream_1 );
            stream_1.Close();
            //计算第二个文件的哈希值
            var stream_2 = new System.IO.FileStream(p_2, System.IO.FileMode.Open);
            var hash_2=GetFileHashCodeInfo(stream_2 );
            stream_2.Close();

           if(hash_1.Item1==hash_2.Item1)
            {
                if(hash_1.Item2==hash_2.Item2)
                    Console.WriteLine("两个文件相等");
                else
                    Console.WriteLine("两个文件不等"); 
            }
            else
                Console.WriteLine("两个文件不等");
        }             

mvc上传文件的时候,我们就可以用以上的思路来去重了:

前端(上传文件用默认的input type:file,上传借用框架:https://github.com/carlcarl/AjaxFileUpload/blob/master/ajaxfileupload.js

以及http://www.oschina.net/code/snippet_105637_50057):

注:今天调试过程中发现一个问题,就是作为文件域(<input type="file">)必须要有name属性,如果没有name属性,上传之后服务器是获取不到图片的。如:正确的写法是<input type="file" id="file1" name="file1" />

<!--Dom标签-->
<tr>
    <td class="title">函件图片:</td>
    <td ><input type = "file" id="file1" accept="image/png,image/gif,image/tiff,image/jpeg"  style="min-width:400px;" /></td>
</tr>
<tr>
    <td></td>
    <td>
        <img id = "image1" src="#" style="max-width:500px;" />
    </td>
</tr>     

 

<script>
    var file = $("#file1")
    file.after(file.clone().val(""));
    //清空已选择的文件内容,对一个文件域(input type=”file”)使用了验证后,我们总会希望把文件域中的值给清空了(否则错误的文件仍然会被提交),而在IE中,安全设置的原因,是不允许更改文件域的值的(也就是不能使用val('')) 
    file.remove(); 
    //选中文件后就前台展示出图片信息
    $('#file1').on('change', function () {
        var file = this.files[0];
        if (this.files && file)
        {
            var reader = new FileReader();
            reader.onload = function(e) {
                            $('#image1').attr('src', e.target.result);
            }
            reader.readAsDataURL(file);
        }
    });
    $('#image1').attr('src', '');

    $.ajaxFileUpload({
        type: 'post',
        url: myurl, 
        secureuri: false, 
        fileElementId: 'file1', 
        dataType: 'json', 
        data: { memo: memo},
        success: function(data, status) {

        },
        error(xhr, status, error){

        }
    });
</script>

后端:

文件hashcode信息库

mvc action方法

HttpFileCollection hfc = System.Web.HttpContext.Current.Request.Files;
           // HttpFileCollectionBase hfc = Request.Files;
            if (hfc.Count !=1 )
            {
                throw new Exception("操作错误,请重新尝试!");
            }
            if (hfc[0].InputStream == null || hfc[0].InputStream.Length == 0)
            {
               throw new Exception("操作错误,请重新尝试!");
            }
            
            Tuple<int,string> hashInfo = ExcelUtils.GetFileHashCodeInfo(hfc[0].InputStream);
            //通过HashCodeSum读取库里数据,然后比对HashCode值
            var list = logic.GetImageInfoList(hashInfo.Item1);
            string imagePath;
            if (list == null || !list.Any(q => q.ImageHashCode == hashInfo.Item2))
            {
                var basePath = "/Image";
                string fileName = $"{ Guid.NewGuid().ToString() }.{ Path.GetExtension(hfc[0].FileName)}";
                string filePath = $"{Server.MapPath(basePath)}\\{fileName}";
                hfc[0].InputStream.Position = 0;
                byte[] buffer = new byte[hfc[0].InputStream.Length];
                hfc[0].InputStream.Read(buffer, 0, (int)hfc[0].InputStream.Length);
                System.IO.File.WriteAllBytes(filePath, buffer);
                imagePath = $"{basePath}/{fileName}";
                logic.AddImageInfo(new ImageInfo() { ImageHashCode = hashInfo.Item2, ImageHashSum = hashInfo.Item1, ImagePath = imagePath });
            }
            else
                imagePath = list.Where(q => q.ImageHashCode == hashInfo.Item2).First().ImagePath;

备注,$.ajaxFileUpload方法说明:

ajaxFileUpload是一个异步上传文件的jQuery插件

  传一个不知道什么版本的上来,以后不用到处找了。

  语法:$.ajaxFileUpload([options])

  options参数说明:

1、url            上传处理程序地址。  
2,fileElementId       需要上传的文件域的ID,即<input type="file">的ID。
3,secureuri        是否启用安全提交,默认为false。 
4,dataType        服务器返回的数据类型。可以为xml,script,json,html。如果不填写,jQuery会自动判断。
5,success        提交成功后自动执行的处理函数,参数data就是服务器返回的数据。
6,error          提交失败自动执行的处理函数。
7,data           自定义参数。这个东西比较有用,当有数据是与上传的图片相关的时候,这个东西就要用到了。
8, type            当要提交自定义参数时,这个参数要设置成post

错误提示:

1,SyntaxError: missing ; before statement错误
  如果出现这个错误就需要检查url路径是否可以访问
2,SyntaxError: syntax error错误
  如果出现这个错误就需要检查处理提交操作的服务器后台处理程序是否存在语法错误
3,SyntaxError: invalid property id错误
  如果出现这个错误就需要检查文本域属性ID是否存在
4,SyntaxError: missing } in XML expression错误
  如果出现这个错误就需要检查文件name是否一致或不存在
5,其它自定义错误
  大家可使用变量$error直接打印的方法检查各参数是否正确,比起上面这些无效的错误提示还是方便很多。 

 

备注:上传大文件,超过4M时候,报:System.Web.HttpException: 超过了最大请求长度!  解决办法如下:

修改web.config文件

<configuration>
  <system.web>
     <httpRuntime maxRequestLength="10000" /><!--10M-->
  </system.web>
<configuration>

 

posted @ 2017-06-07 17:36  lcawen  阅读(1000)  评论(0)    收藏  举报