65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.97/5 (18投票s)

2015年8月4日

MIT

4分钟阅读

viewsIcon

22425

downloadIcon

1045

一个 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

© . All rights reserved.