文件比较和哈希扩展(Windows 资源管理器)






4.97/5 (18投票s)
一个 Windows 资源管理器扩展,用于方便地进行二进制/文本文件比较,以及计算 MD5、SHA1、SHA256 哈希值。
*我建议您从 codeplex TFS 下载最新的代码和二进制文件。
引言
这是一个 Windows 资源管理器的外壳扩展,可以方便地进行二进制或文本文件比较
以及计算选定文件的 MD5、SHA1、SHA256 哈希值。
背景
文件比较和完整性工具已经存在了很长时间。即使是 MS-DOS 也有一个(只需在 DOS 命令提示符下输入 fc /? 即可),但使用它们并不十分用户友好。
Windows 资源管理器允许使用实现特定接口的 COM 对象作为扩展,而这种集成通常非常方便。
.Net 和一些库,如 Dave Kerr 的 工具,使得编写外壳扩展变得容易得多。
此外,还有一些不错的文本差异工具,如 Christopher Erker 的 DeltaScope,它们缺少外壳集成,所以我把这些部分组合起来,加入了我的一些想法,比如 Levenshtein 距离,并创建了这个旨在易于使用并同时提供有用功能的扩展。
使用代码
Windows 资源管理器集成代码严重依赖于 SharpShell 项目。为了让您了解如何向 Windows 资源管理器上下文菜单添加其他项,这里有一个扩展 SharpContextMenu
类的代码片段。
ContextMenuStrip _menu;
ToolStripMenuItem _binaryCompareItem;
ToolStripMenuItem _textCompareItem;
ToolStripMenuItem _binaryCompare2Items;
ToolStripMenuItem _textCompare2Items;
ToolStripMenuItem _md5Item;
ToolStripMenuItem _sha1Item;
ToolStripMenuItem _sha256Item;
ToolStripMenuItem _aboutItem;
ToolStripMenuItem _rootItem;
/// <summary>
/// Creates the context menu. This can be a single menu item or a tree of them.
/// </summary>
/// <returns>
/// The context menu for the shell context menu.
/// </returns>
protected override ContextMenuStrip CreateMenu()
{
// Create the menu strip.
_menu = new ContextMenuStrip();
// Create a menu item to hold all of the subitems.
_rootItem = new ToolStripMenuItem
{
Text = "Compare&&Hash",
Image = FileCompareByHash.Resource.compare22
};
// Now add the child items.
_binaryCompareItem = new ToolStripMenuItem{Text = "Binary Compare with...",};
_binaryCompareItem.Click += (sender, args) => CompareAgainst(sender as ToolStripMenuItem);
_textCompareItem = new ToolStripMenuItem { Text = "Text Compare with..." };
_textCompareItem.Click += (sender, args) => CompareAgainst(sender as ToolStripMenuItem);
_binaryCompare2Items = new ToolStripMenuItem { Text = "Compare binary files...", };
_binaryCompare2Items.Click += (sender, args) => ShowComparison(true);
_textCompare2Items = new ToolStripMenuItem { Text = "Compare text files...", };
_textCompare2Items.Click += (sender, args) => ShowComparison(false);
_md5Item = new ToolStripMenuItem{Text = "Calculate MD5",};
_md5Item.Click += (sender, args) => ShowHash<MD5CryptoServiceProvider>();
_sha1Item = new ToolStripMenuItem{Text = "Calculate SHA1",};
_sha1Item.Click += (sender, args) => ShowHash<SHA1CryptoServiceProvider>();
_sha256Item = new ToolStripMenuItem{Text = "Calculate SHA256",};
_sha256Item.Click += (sender, args) => ShowHash<SHA256CryptoServiceProvider>();
_aboutItem = new ToolStripMenuItem{Text = "About...",};
_aboutItem.Click += (sender, args) => About(this);
// Add all the items.
_rootItem.DropDownItems.Add(_binaryCompareItem);
_rootItem.DropDownItems.Add(_textCompareItem);
_rootItem.DropDownItems.Add(_binaryCompare2Items);
_rootItem.DropDownItems.Add(_textCompare2Items);
_rootItem.DropDownItems.Add(new ToolStripSeparator());
_rootItem.DropDownItems.Add(_md5Item);
_rootItem.DropDownItems.Add(_sha1Item);
_rootItem.DropDownItems.Add(_sha256Item);
_rootItem.DropDownItems.Add(new ToolStripSeparator());
_rootItem.DropDownItems.Add(_aboutItem);
// Add the item to the context menu.
_menu.Items.Add(_rootItem);
if (_menu != null)
{
UpdateMenu();
}
// Return the menu.
return _menu;
}
private void UpdateMenu()
{
int itemcnt = SelectedItemPaths.Count();
switch (itemcnt)
{
case 1:
_rootItem.DropDownItems.Remove(_textCompare2Items);
_rootItem.DropDownItems.Remove(_binaryCompare2Items);
break;
case 2:
_rootItem.DropDownItems.Remove(_textCompareItem);
_rootItem.DropDownItems.Remove(_binaryCompareItem);
break;
default:
_rootItem.DropDownItems.Remove(_textCompare2Items);
_rootItem.DropDownItems.Remove(_binaryCompare2Items);
_rootItem.DropDownItems.Remove(_textCompareItem);
_rootItem.DropDownItems.Remove(_binaryCompareItem);
_rootItem.DropDownItems.RemoveAt(0);//the separator
break;
}
}
SharpShell 的内部工作原理超出了本文的范围,我鼓励您访问提供的链接中的文章。我从 codeproject 借来的另一大块软件(稍作修改)是关于显示文件差异的,这也超出了本文的范围。
我的一项值得注意的添加是使用 Levenshtein 距离 计算文本文件的相似性,用于文本文件比较。
我用它只是为了给您一个文本内容相关程度的想法。它应该在小型文本文件上运行得不错。
下面是我用来计算它的代码。
static class Levensthein
{
//*****************************
// Compute Levenshtein distance
//*****************************
public static void Reset()
{
_costMatrix = null;
}
static ushort[,] _costMatrix = null;
static public ushort LD(string s, string t)
{
ushort n = (ushort)s.Length; //length of s
ushort m = (ushort)t.Length; //length of t
//reallocate only if necessary
if (_costMatrix == null || _costMatrix.GetUpperBound(0) < n || _costMatrix.GetUpperBound(1) < m)
_costMatrix = new ushort[n + 1, m + 1]; // matrix
ushort cost; // cost
// Step 1
if (n == 0) return m;
if (m == 0) return n;
// Step 2
for (ushort i = 0; i <= n; _costMatrix[i, 0] = i++) ;
for (ushort j = 0; j <= m; _costMatrix[0, j] = j++) ;
// Step 3
for (ushort i = 1; i <= n; i++)
{
//Step 4
for (ushort j = 1; j <= m; j++)
{
// Step 5
if (s[i - 1] == t[j - 1])
cost = 0;
else
cost = 1;
// Step 6
_costMatrix[i, j] = (ushort)System.Math.Min(System.Math.Min(_costMatrix[i - 1, j] + 1, _costMatrix[i, j - 1] + 1),
_costMatrix[i - 1, j - 1] + cost);
}
}
// Step 7
return _costMatrix[n, m];
}
}
使用资源管理器扩展
比较两个文本文件
如上图所示,要比较 2 个文本文件,请选中它们,右键单击选中的文件,然后在弹出菜单中导航到“Compare&Hash”->“Compare text files...” 或 “Compare binary files...”。
如果文件位于不同的文件夹或驱动器上,您还需要额外一步,如下所示。
比较不同文件夹中的两个文件
当要比较的文件位于不同的目录中时,选择第一个文件,右键单击它,然后选择“Text Compare with...”或“Binary Compare with...”。将出现一个文件对话框,用于选择要比较的文件。选择第二个文件,然后单击“Open”。根据您的选择,消息框将显示文本差异,或者告诉您文件是否相同。
您可以选择继续检查选定文件之间的差异,例如大小、修改时间,或为它们计算特定的哈希值。
获取单个文件的哈希值
右键单击文件,选择哈希算法,然后您将可以选择将特定哈希值复制到剪贴板。
获取同一文件夹中多个文件的哈希值
如果所有要哈希的文件都在同一个文件夹中,您可以选择它们,右键单击并选择哈希算法。将出现一个消息框,显示选定的文件及其各自的哈希值,如下所示。
关注点
您可以下载完整的源代码来重新构建我的此扩展项目,并制作安装脚本,但与 SharpShell 相关的任何内容仅以二进制形式存在(再次参见提供的代码和更多信息的链接)。
还有一个下载,包含一个带有安装/卸载脚本的 zip 文件,方便您使用,其中只包含二进制文件。
在使用它之前,您应该知道关于 在 Windows 资源管理器中托管 CLR 的争论,这个代码就是这样做的,但尚未得出最终结论。
底线是,只要您使用的是 .net 4.0 或更高版本,您就很可能是安全的。我在 Windows 7 上测试过此代码,没有遇到任何问题。
历史
2015 年 8 月:发布版本 1.2。
如果您想确保获得最新的、最更新的代码和二进制文件,请访问 codeplex。