如果一张图片被用两个不同的文件名保存了两次,有没有办法比较它们是否相同..?
我希望基本的哈希或CRC类型检查可以起作用..?
文件大小可能不行,因为池中有数百万张图片,不同的图片可能具有相同的大小..
希望在C#中有一种简单的方法来实现它..
SHA256
类是一个不错的选择,尽管可能有点过头。例如:static byte[] Sha256HashFile(string file)
{
using (SHA256 sha256 = SHA256.Create())
{
using (Stream input = File.OpenRead(file))
{
return sha256.ComputeHash(input);
}
}
}
比较返回的两个字节数组最简单的方法可能是使用 Convert.ToBase64
将它们都转换为字符串,然后比较这两个字符串。虽然丑陋但容易 :) 你也可以使用 Enumerable.SequenceEqual
:
byte[] hash1 = Sha256HashFile("file1.png");
byte[] hash2 = Sha256HashFile("file2.png");
bool same = hash1.SequenceEqual(hash2);
如果您想将哈希值存储为集合或字典,您可以自己实现IEqualityComparer<byte[]>
,但坦率地说,使用base64字符串最容易。例如,这将打印出重复的文件:
var hashToNameMap = new Dictionary<string, string>();
foreach (string file in files)
{
byte[] hash = Sha256HashFile(file);
string base64 = Convert.ToBase64(hash);
string existingName;
if (hashToNameMap.TryGetValue(base64, out existingName))
{
Console.WriteLine("{0} is a duplicate of {1}", file, existingName);
}
else
{
hashToNameMap[base64] = file;
}
}
几点说明:
你如何处理这个问题取决于你的目标是绝对速度、代码简单性等。这也可能取决于池是否会随着时间的推移而增长 - 例如,你可能想要在获得两个或更多大小相同的文件时立即对文件进行哈希,这样当你添加另一个大小相同的文件时,你可以哈希那个文件并添加它,而无需重新读取现有数据。
首先,无论如何都要检查长度。只有在它们匹配时,您才需要深入了解。
对于所有具有相同大小的图像,请计算哈希值。当哈希值匹配时,您可以相当确定这些图像是相同的。该库提供了许多加密安全哈希,但您可能希望寻找优化:
采样。如果您的图像很大(>100kB),则可以通过仅计算几个段上的哈希来节省I/O。开头、中间和结尾的几KB可能足以获得良好的指纹。请使用512的倍数作为块的大小和偏移量。Jpeg压缩的工作方式有点像哈希:少量像素的差异通常会导致位流中的大差异。
使用更快的哈希。在这种情况下,简单的异或算法可能就足够了。
如果您真的想一次比较两个图像,那么请使用一个哈希实现,让您检查中间结果。一旦出现差异,您就可以停止。
在
System.Security.Cryptography;
使用SHA1
using(SHA1 sha = SHA1.Create()) { //added using based on Jon Skeet comment
byte[] newData = sha.ComputeHash(data);
}
data是文件的byte[]数据
newData是哈希值
仅当您想知道两个图像文件是否完全相同(即字节相同),而不是它们是否只编码了相同的像素(如果元数据不同,则可能是不同的文件)时,才适用此方法。
你可以从每个文件中读取二进制,然后比较所包含的二进制。同一张图片在每个数组中应该具有完全相同的二进制。
只是一个想法。
你也可以像这样做
public string ImageToBase64(Image image,
System.Drawing.Imaging.ImageFormat format)
{
using (MemoryStream ms = new MemoryStream())
{
// Convert Image to byte[]
image.Save(ms, format);
byte[] imageBytes = ms.ToArray();
// Convert byte[] to Base64 String
string base64String = Convert.ToBase64String(imageBytes);
return base64String;
}
}
然后你可以使用String.Compare()
。对于较大的图片来说,这可能会比较慢,因为它会生成一个相当大的字符串,但我仍然发布了它,只是为了完整性而已 :)