private void btn删除勾选的文件_Click(object sender, EventArgs e)
        {
            TreeNode[] tns = this.获取已经勾选复选框的节点(this.treeView冗余文件.Nodes);
            foreach (TreeNode tmp in tns)
            {
                文件信息摘要 fi = tmp.Tag as 文件信息摘要;
                if (fi == null)
                {
                    continue;
                }

                if (!System.IO.File.Exists(fi.FileName))
                {
                    continue;
                }

                System.IO.File.SetAttributes(fi.FileName, System.IO.FileAttributes.Normal);
                System.IO.File.Delete(fi.FileName);
                this.成功清理文件总数++;
                this.设置节点文本(tmp, string.Format("[删除完成] {0}", fi.FileName));
            }

            this.设置进度提示(string.Format("冗余文件数:{0} 清理文件数:{1}"
                                      , this.冗余文件总数
                                      , this.成功清理文件总数)
                        );
            this.重新计算输出信息操作界面状态();
        }
        private void 重新计算输出信息操作界面状态()
        {
            if (this.InvokeRequired)
            {
                VoidHandler d = new VoidHandler(this.重新计算输出信息操作界面状态);
                this.Invoke(d);
            }
            else
            {
                this.btn全部展开.Enabled = this.展开全部节点ToolStripMenuItem.Enabled = (this.treeView冗余文件.Nodes.Count > 0);
                this.btn全部折叠.Enabled = this.折叠全部节点ToolStripMenuItem.Enabled = (this.treeView冗余文件.Nodes.Count > 0);
                this.btn清空输出.Enabled = this.除全部节点ToolStripMenuItem.Enabled = (this.treeView冗余文件.Nodes.Count > 0);

                {
                    bool 显示用记事本打开菜单 = false;
                    if (this.treeView冗余文件.SelectedNode != null)
                    {
                        文件信息摘要 fi = this.treeView冗余文件.SelectedNode.Tag as 文件信息摘要;
                        if (fi != null && System.IO.File.Exists(fi.FileName))
                        {
                            显示用记事本打开菜单 = true;
                        }
                    }
                    this.用记事本打开ToolStripMenuItem.Enabled = 显示用记事本打开菜单;
                    this.运行ToolStripMenuItem.Enabled     = 显示用记事本打开菜单;
                }

                {
                    bool       显示删除选中的冗余文件菜单 = false;
                    TreeNode[] tns           = this.获取已经勾选复选框的节点(this.treeView冗余文件.Nodes);
                    foreach (TreeNode tmp in tns)
                    {
                        文件信息摘要 fi = tmp.Tag as 文件信息摘要;
                        if (fi == null)
                        {
                            continue;
                        }

                        if (!System.IO.File.Exists(fi.FileName))
                        {
                            continue;
                        }

                        显示删除选中的冗余文件菜单 = true;
                        break;
                    }
                    this.btn删除勾选的文件.Enabled = this.除选中的冗余文件ToolStripMenuItem.Enabled = 显示删除选中的冗余文件菜单;
                }
            }
        }
        private void treeView冗余文件_BeforeCheck(object sender, TreeViewCancelEventArgs e)
        {
            文件信息摘要 fi = e.Node.Tag as 文件信息摘要;

            if (fi == null)
            {
                e.Cancel = true;
                return;
            }

            if (System.IO.File.Exists(fi.FileName) == false)
            {
                e.Cancel = true;
                return;
            }
        }
        private void 运行ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            文件信息摘要 fi = this.treeView冗余文件.SelectedNode.Tag as 文件信息摘要;

            if (fi == null)
            {
                return;
            }

            string fileName = fi.FileName;

            if (!System.IO.File.Exists(fileName))
            {
                return;
            }

            System.Diagnostics.Process.Start(fileName);
        }
        private void 文件处理方法()
        {
            this.设置文件列表面板Enabled属性(false);
            this.文件处理线程起始执行时间 = System.DateTime.Now;
            this.设置开始按钮文本("停止");
            this.设置进度条当前值(0);
            this.当前处理的文件索引 = 0;
            this.冗余文件总数    = 0;
            this.成功清理文件总数  = 0;
            this.清空节点();
            this.启动或停止提示信息计时器(true);

            #region 开始添加文件
            this.当前正在执行的步骤 = 当前执行步骤.正在统计需要处理的文件;
            this.设置操作项提示("正在统计需要处理的文件……");
            this.设置进度提示("");
            this.文件信息摘要集合.Clear();
            foreach (string tmp in this.lb文件列表.Items)
            {
                System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(tmp);

                if ((di.Attributes & System.IO.FileAttributes.Directory) == System.IO.FileAttributes.Directory)
                {
                    if (!System.IO.Directory.Exists(di.FullName))
                    {
                        continue;
                    }
                    this.添加目录(di.FullName);
                }
                else
                {
                    if (!System.IO.File.Exists(di.FullName))
                    {
                        continue;
                    }
                    this.添加文件信息摘要(di.FullName);
                }
            }
            #endregion

            this.设置进度条最大值(this.文件信息摘要集合.Count);
            #region 搜索冗余文件。
            {
                this.当前正在执行的步骤 = 当前执行步骤.正在计算冗余文件;
                System.Collections.Generic.List <文件信息摘要> SameFiles = new System.Collections.Generic.List <文件信息摘要>();
                for (int i = 0; i < this.文件信息摘要集合.Count - 1; i++)
                {
                    this.当前处理的文件索引 = i;

                    文件信息摘要 tmpi = this.文件信息摘要集合[i];
                    if (tmpi.IsRepeat)//如果此文件已经比较过并且明确为冗余文件,则跳过此文件不进行比较。
                    {
                        continue;
                    }

                    #region 寻找与当前文件相同的冗余文件。
                    SameFiles.Clear();
                    for (int j = i + 1; j < this.文件信息摘要集合.Count; j++)
                    {
                        文件信息摘要 tmpj = this.文件信息摘要集合[j];
                        if (tmpj.IsRepeat)//如果此文件已经比较过并且明确为冗余文件,则跳过此文件不进行比较。
                        {
                            continue;
                        }
                        if (tmpi.Length == tmpj.Length)
                        {
                            if (string.IsNullOrEmpty(tmpi.SHA1))
                            {
                                tmpi.SHA1 = 计算文件的SHA1(tmpi.FileName).Replace("-", "");
                            }
                            if (string.IsNullOrEmpty(tmpj.SHA1))
                            {
                                tmpj.SHA1 = 计算文件的SHA1(tmpj.FileName).Replace("-", "");
                            }
                            if (tmpi.SHA1 == tmpj.SHA1)
                            {
                                if (CompareFile(tmpi.FileName, tmpj.FileName))
                                {
                                    SameFiles.Add(tmpj);
                                    tmpj.IsRepeat = true;
                                }
                            }
                        }
                    }
                    #endregion

                    #region 将冗余文件添加到记录集。
                    if (SameFiles.Count > 0) //如果存在冗余文件。
                    {
                        TreeNode rootTreeNode = new TreeNode();
                        {
                            TreeNode subTreeNode = new TreeNode();
                            subTreeNode.Text = tmpi.FileName;
                            subTreeNode.Tag  = tmpi;
                            this.添加节点(rootTreeNode.Nodes, subTreeNode);
                        }

                        this.冗余文件总数 += SameFiles.Count;
                        foreach (文件信息摘要 tmp in SameFiles)
                        {
                            TreeNode subTreeNode = new TreeNode();
                            subTreeNode.Text = tmp.FileName;
                            subTreeNode.Tag  = tmp;
                            this.添加节点(rootTreeNode.Nodes, subTreeNode);
                        }
                        this.设置节点文本(rootTreeNode, string.Format("冗余文件 {0} 个 [大小:{2} Byte]:> {1}", SameFiles.Count, tmpi.FileName, tmpi.Length));
                        this.添加节点(this.treeView冗余文件.Nodes, rootTreeNode);
                    }
                    #endregion
                }
            }
            #endregion

            #region 清理冗余文件。
            if (this.treeView冗余文件.Nodes.Count > 0 && this.cb删除文件内容相同的冗余文件.Checked) //如果存在冗余文件。
            {
                this.当前正在执行的步骤 = 当前执行步骤.正在删除冗余文件;
                bool 是否指定了清理目录 = !string.IsNullOrEmpty(this.tb只从这里清理.Text);
                this.设置树视图更新状态(false);
                foreach (TreeNode rootNode in this.treeView冗余文件.Nodes)
                {
                    if (rootNode.Nodes.Count < 2)
                    {
                        continue;
                    }

                    int startIndex = (是否指定了清理目录 ? 0 : 1); //如果设置清理目录则从 0 开始遍历;否则从 1 开始遍历,保留第一个节点。
                    for (int i = startIndex; i < rootNode.Nodes.Count; i++)
                    {
                        TreeNode subNode = rootNode.Nodes[i];
                        文件信息摘要   tmp     = subNode.Tag as 文件信息摘要;
                        if (是否指定了清理目录 && tmp.FileName.StartsWith(this.tb只从这里清理.Text) == false)
                        {
                            continue;
                        }

                        try
                        {
                            System.IO.File.SetAttributes(tmp.FileName, System.IO.FileAttributes.Normal);
                            System.IO.File.Delete(tmp.FileName);
                            this.成功清理文件总数++;
                            this.设置节点文本(subNode, string.Format("[删除完成] {0}", tmp.FileName));
                        }
                        catch (System.Exception ex)
                        {
                            MessageBox.Show(ex.ToString());
                        }
                    }
                }
            }
            #endregion

            this.停止文件处理线程(false);
        }