2012-01-10 54 views
3

我试图从用户在我的web应用程序上传的图像的字节数组中创建一个MD5字符串..这是因为我想图像分散在不同的文件夹中。 而我不必使用userID作为文件夹名称。看起来更专业。创建上传图像的MD5哈希

结果会是这样的:

/images/ 'first-two-char-of-md5'/'the-complete-md5-string'.[jpg,png,bmp....] 

这听起来是一个很好的解决方案来处理图像?

所以。 我的代码(东西从互联网上。):

protected void btnUpload_Click(object sender, EventArgs e) 
    { 
     if (FileUpload1.HasFile) 
     { 
      if (CheckFileType(FileUpload1.FileName)) 
      { 
       const int BUFFER_SIZE = 255; 
       Byte[] Buffer = new Byte[BUFFER_SIZE]; 

       Stream theStream = FileUpload1.PostedFile.InputStream; 
       nBytesRead = theStream.Read(Buffer, 0, BUFFER_SIZE); 

       System.Text.ASCIIEncoding ASCIIEncoding = new ASCIIEncoding(); 
       System.Text.UTF8Encoding utf8 = new UTF8Encoding(); 
       //Just trying some stuff to see the output... 
       Label1.Text = ASCIIEncoding.GetString(CalculateMD5(theStream)) + "<br>" + utf8.GetString(CalculateMD5(theStream)) + "<br>" + Convert.ToBase64String(CalculateMD5(theStream)); 
      } 
     } 
    } 


private static byte[] _emptyBuffer = new byte[0]; 

    public static byte[] CalculateMD5(Stream stream) 
    { 
     return CalculateMD5(stream, 64 * 1024); 
    } 

    public static byte[] CalculateMD5(Stream stream, int bufferSize) 
    { 
     MD5 md5Hasher = MD5.Create(); 

     byte[] buffer = new byte[bufferSize]; 
     int readBytes; 

     while ((readBytes = stream.Read(buffer, 0, bufferSize)) > 0) 
     { 
      md5Hasher.TransformBlock(buffer, 0, readBytes, buffer, 0); 
     } 

     md5Hasher.TransformFinalBlock(_emptyBuffer, 0, 0); 

     return md5Hasher.Hash; 
    } 

结果。我从“calculateMD5()”得到一些输出,但是当我试图把它放到label1。看看发生了什么。只有一堆奇特的人物。 我在这里做错了什么?我希望它是htmlsafe ... a-z,A-Z,只有0-9。

回答

7

散列正以字节数组形式返回。您需要将其转换为人类可读的格式,例如73868cb1848a216984dca1b6b0ee37bc。通过从哈希运算返回的字节列表

var s = new StringBuilder(); 
foreach (byte b in md5Hasher.Hash) 
    s.Append(b.ToString("x2").ToLower()); 
return s.ToString(); 

这种迭代,并且每个字节十六进制转换:您可以使用类似下面。你可以在format strings you can use for the byte type on MSDN找到更多的信息。

要回答你的问题的第一部分:

这听起来是一个很好的解决方案来处理图像?

它应该是足够的,虽然如果2个用户上传相同的图像,那么它会导致相同的散列。您可以尝试使用用户名和时间戳腌制数据来减轻这一点。

您还需要一些检查,因为即使可能性非常小,您可能会为不同的图像/用户生成相同的散列('冲突'),并且您不希望用户覆盖另一个用户图片。您可以通过生成图像的散列来检查它是否已经存在,并且如果存在,请向预散列数据添加一些字节,直到散列是唯一的。

+0

谢谢!关于具有相同图像的2个用户。你认为有可能将userID添加到_emptybuffer字节[],在我的情况是空的(我认为),添加盐? – Easyrider 2012-01-10 11:59:46

+1

是的,这应该工作。 MD5使用校验和来计算最终的散列,'TransformFinalBlock'是一种说法'这里是最后一个数据,并且完成散列操作'。或者,您可以将任何其他数据写入到传递给'CalculateMD5'的流的末尾(可能会先将图像数据读入中间的'MemoryStream',追加额外的数据并将'MemoryStream'传递给'CalculateMD5' )。 – mdm 2012-01-10 13:26:03

2

您无法读取它,因为它是一个字节数组,它需要使用适当的编码转换为可读的字符串。

例如在SHA256类来生成散列:

using (System.Security.Cryptography.SHA256 sha = System.Security.Cryptography.SHA256.Create()) 
     return sha.ComputeHash(data); 

那么如果你想为一个字符串,看看成可读的形式:

string hashValue = Convert.ToBase64String(hash); 

当然也有other算法除SHA256和MD5之外,还生成散列(带或不带盐)。

0

你试过CalculateMD5(theStream).ToString()吗?不知道它是否会有所帮助,但可能值得一试。

此外,我会建议你保存CalculateMD5(theStream)在一个局部变量,然后.ToString()它的结果。

GL,希望有所帮助。

+0

不,这不行。 'Console.WriteLine((new byte [] {1,2,3})。ToString());'打印'System.Byte []'这不是所需的输出。 – mdm 2012-01-10 11:34:49

3

还有BitConverter类,它有一个ToString()方法可以将字节数组转换为它们的十六进制字符串表示形式。

因此,像:

BitConverter.ToString(CalculateMD5(theStream)).Replace("-",""); 

会得到你,MD5哈希的典型的十六进制字符串表示。