黑马程序员学习日记(4)——文件批量重命名程序:One Click容错算法

---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、<a href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! ----------------------


前言:很多时候,用户并不会像我们想的那样去把每个选项都填对


既然世上没有完美的用户,那么,我们唯有让软件拥有更优秀的容错能力。

接下来我将讲解和分析这个软件到底具有多强的容错能力。(若有大神路过请轻拍。。)


1.首先我在ColorString发布了一个TextChanged事件,这个事件在修改ColorString类型的Text属性(也就是当用户输入)时会被触发,它将用于检查用户的输入是否正确。

        /// <summary>
        /// 这个类用于创建带有颜色的文本
        /// </summary>
        public class ColorString : INotifyPropertyChanged
        {
            public delegate void TextHelper();
            public event TextHelper TextChanged;

            /// <summary>
            /// 每次对Text修改都会触发事件,检查输入
            /// </summary>
            public string Text // 文本属性
            { 
                get { return text; } 
                set 
                {
                    text = value;
                    if (TextChanged != null)
                    {
                        TextChanged(); 
                    }
                    if (PropertyChanged != null)
                    {
                        PropertyChanged(this, new PropertyChangedEventArgs("Text"));
                    }
                }
            }
        }

2.提供函数注册ColorString成员的事件,当我们修改文件类型和文件名时,程序会检查这些输入是否正确,并给出响应。

        private Rename()
        {
            customName = new ColorString() { Color = ColorString.TextColor.Black, Text = null, Visibility = true };
            specifiedType = new ColorString() { Color = ColorString.TextColor.Black, Text = null, Visibility = true };

            customName.TextChanged += CheckCustomName;
            specifiedType.TextChanged += CheckSpecifiedType;
        }
但并不是所有成员都需要注册事件,因为帮助消息和目录路径都需要合法的途径才能修改,所以不需要检查它们。

        public FileOperator()
        {
            message = new ColorString() { Color = ColorString.TextColor.Red, Text = null, Visibility = false };
            directoryPath = new ColorString() { Color = ColorString.TextColor.Black, Text = null, Visibility = true };
        }

3.接下来我将逐一讲解这些容错算法,并演示它们
首先是对目录路径的判断,由于我把它设置为只能通过Cofd.ShowDialog()修改,不能通过直接在文本框输入来修改,所以我们只需要判断这个目录是否为空即可。如果目录为空,显示消息提醒用户。

        /// <summary>
        /// 使用CommonOpenFileDialog类打开包含要重命名文件的文件夹
        /// </summary>
        public void GetTheDirectory()
        {            
            // Add reference from Windows API code pack : 
            //     Microsoft.WindowsAPICodePack
            //     Microsoft.WindowsAPICodePack.Shell
            //
            // using Microsoft.WindowsAPICodePack.Dialogs;
            // Down Link : http://archive.msdn.microsoft.com/WindowsAPICodePack/Release/ProjectReleases.aspx?ReleaseId=4906#VoteBreakdown
            // 这些程序集的安装文件已下载到解决方案中,解压即可用

            using (Cofd = new CommonOpenFileDialog())
            {
                Cofd.IsFolderPicker = true;	// true: 文件夹, false: 文件
                Cofd.Title = "选择一个文件夹";                                                             // 标题
                Cofd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); // 初始路径

                // 如果成功打开目录
                if (Cofd.ShowDialog() == CommonFileDialogResult.Ok) 
                {
                    // 为路径赋值
                    DirectoryPath.Text = Cofd.FileName;

                    // 检查目录是否为空
                    CheckTheDirectory();
                }  
            }
        }
        public void CheckTheDirectory()
        {
            // 文件夹是否为空
            IsInputRightOrWrong(Directory.GetDirectories(DirectoryPath.Text).Length <= 0 && Directory.GetFiles(DirectoryPath.Text).Length <= 0,
                string.Format("*提醒:①{0}为空文件夹!", System.IO.Path.GetFileName(DirectoryPath.Text)), ref directoryPath);
        }

        /// <summary>
        /// 根据条件是否正确显示不同的信息
        /// </summary>
        /// <param name="condition">条件</param>
        /// <param name="warning">如果条件正确,将打印消息</param>
        /// <param name="input">如果条件正确,用户的输入变为红色</param>
        public void IsInputRightOrWrong(bool condition, string warning, ref ColorString input)
        {
            if (condition)
            {
                // 显示消息提醒用户
                Message.Visibility = true;
                Message.Color = ColorString.TextColor.Red;
                Message.Text = warning;

                // 输入变为红色,提醒用户
                input.Color = ColorString.TextColor.Red;
            }
            else
            {
                // 输入为黑色
                input.Color = ColorString.TextColor.Black;

                // 判断其他所有输入都正确
                AllGreen();
            }
        }
演示:


4.接下来是对文件类型输入的判断。在这里我只做了简单的判断:首先输入不能小于2,并且输入的开始必须是"*."

如果用户输入的类型符合上面要求,但实际上不存在这个类型(如*.abcdefg),程序还是会正常执行,最终的结果是当用户单击"一键完成",会提示用户成功重命名0个文件,很明显这不是用户想要的。我很遗憾我只做到了这个地步,因为要与所有的类型作判断需要我花很多的精力去研究,现阶段我只能先放弃,把重点放在其他地方上,如果有人想到更好的算法,请一定联系我,与我分享。

        /// <summary>
        /// 检查用户输入的文件类型的拼写是否正确,错误将弹出提示
        /// </summary>
        private void CheckSpecifiedType()
        {
            // 把输入转换为小写(暂时删除事件确保赋值操作不会造成无限循环)
            specifiedType.TextChanged -= CheckSpecifiedType;
            specifiedType.Text = specifiedType.Text.ToLower();
            specifiedType.TextChanged += CheckSpecifiedType;

            // 如果输入小于2或文件类型的拼写不正确
            IsInputRightOrWrong(SpecifiedType.Text.Length <= 1 || SpecifiedType.Text.Substring(0, 2) != "*.",
                "*提醒:②文件类型的填写格式不正确!", ref specifiedType);
        }

5.再来是对输入的文件名的判断,我在这上面花了差不多一天的时间去研究

在上代码前,我先分析一下文件名的构成:文件名必须包含[n1,n2],n1表示文件的起始序号,n2表示序号最小位数,n1的位数小于n2自动用前导0补充。示例:Photo_[1,3]



        private int n1, n2;                              // 代表用户输入的2个参数
        private string brackets;                         // 用于从startLeftParenthesis中截取参数列表

        /// <summary>
        /// 判断用户的输入是否包含参数列表[n1,n2],如果不包含将弹出提示
        /// </summary>
        private void CheckCustomName()
        {
            bool ParameterListFormatIsRight = false; // 代表用户输入的参数列表格式是否正确
            string startLeftParenthesis = "";        // 截取一个从‘[’开始到输入结尾的字符串            

            int indexOfLeftParenthesis = -1;        // 左括号的索引
            int indexOfRightParenthesis = -1;       // 右括号的索引
            bool isStringHaveParameterList = false; // 检查是否搜到参数列表(但不保证格式是否正确)


            // 搜索第一对括号所在的索引:如果能搜索到‘[',尝试搜索‘]’
            if ((indexOfLeftParenthesis = customName.Text.IndexOf('[')) != -1)
            {
                // 尝试搜索‘]’
                indexOfRightParenthesis = customName.Text.Substring(indexOfLeftParenthesis).IndexOf(']');

                // 如果搜索到‘]’,isStringHaveParameterList为true
                isStringHaveParameterList = indexOfRightParenthesis != -1;

                // 截取一个从‘['开始到输入结尾的字符串
                startLeftParenthesis = customName.Text.Substring(indexOfLeftParenthesis);
            }         

            #region 如果customName包含参数列表,判断customName是否有包含格式正确的参数列表
            while (isStringHaveParameterList == true)
            {
                // 截取参数列表
                brackets = startLeftParenthesis.Substring(0, startLeftParenthesis.IndexOf(']') + 1);

                // 把用户可能输入的","改为","(根据用户习惯,废除这项容错功能。用户一般不会在输入'['后输入',',因为这需要切换中英文输入法)
                //brackets.Replace(',', ',');

                #region 如果参数列表没有","
                if (brackets.Contains(',') == false)
                {
                    // 没有",",说明该参数列表不符合规范,搜索下一个参数列表
                    IsNewStringHaveParameterList(ref startLeftParenthesis, ref indexOfLeftParenthesis, ref indexOfRightParenthesis,
                            ref isStringHaveParameterList);
                    continue;
                }
                #endregion

                #region 如果参数列表有",",检查2个参数
                else
                {
                    // 截取参数列表第一个参数
                    string s1 = brackets.Substring(1, brackets.IndexOf(',') - 1);
                    // 截取参数列表第二个参数
                    string s2 = brackets.Substring(brackets.IndexOf(',') + 1, brackets.IndexOf(']') - brackets.IndexOf(',') - 1);

                    // isN1AInt表示第一个参数是否为数字
                    bool isN1AInt = int.TryParse(s1, out n1);
                    // isN2AInt表示第二个参数是否为数字
                    bool isN2AInt = int.TryParse(s2, out n2);

                    // 如果参数列表包含的不是数字
                    if (isN1AInt == false || isN2AInt == false)
                    {
                        // 该参数列表不符合规范,搜索下一个参数列表
                        IsNewStringHaveParameterList(ref startLeftParenthesis, ref indexOfLeftParenthesis, ref indexOfRightParenthesis,
                            ref isStringHaveParameterList);
                        continue;
                    }
                    // 如果参数列表格式完全正确
                    else
                    {
                        // 退出循环
                        ParameterListFormatIsRight = true;
                        break;
                    }
                }
                #endregion
            }
            #endregion

            // 如果customName不包含格式正确的参数列表,将显示消息提醒用户
            IsInputRightOrWrong(ParameterListFormatIsRight == false,
                "*提醒:③缺少参数列表或参数列表格式不正确,参数列表是否缺少\",\"或输入了不合法字符?", ref customName);
        }

        private static void IsNewStringHaveParameterList(ref string startLeftParenthesis,
            ref int indexOfLeftParenthesis, ref int indexOfRightParenthesis, ref bool isStringHaveParameterList)
        {
            // 这个参数列表格式不正确,去掉当前的'[',检查这段字符串
            string stringWithOutOldLeftParenthesis = startLeftParenthesis.Substring(1);

            // 检查stringWithOutOldLeftParenthesis是否包含'['
            indexOfLeftParenthesis = stringWithOutOldLeftParenthesis.IndexOf('[');

            // 如果stringWithOutOldLeftParenthesis包含'['
            if (indexOfLeftParenthesis != -1)
            {
                // 更新startLeftParenthesis,以便下次截取
                startLeftParenthesis = stringWithOutOldLeftParenthesis.Substring(indexOfLeftParenthesis);

                // 尝试搜索']'
                indexOfRightParenthesis = startLeftParenthesis.IndexOf(']');
                // 判断是否存在参数列表
                isStringHaveParameterList = indexOfRightParenthesis != -1;
            }
            else
            {
                isStringHaveParameterList = false;
            }
        }

这里采取的判断是:


经测试容错性能非常好:(这里的测试改为搜索第一个有效参数列表的'['索引,搜索不到返回-1)



容错算法的讲解就到这里。

下一篇文章将讲解Run()的实现。


---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、<a href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! ----------------------

详细请查看:<a href="http://www.itheima.com" target="blank">www.itheima.com</a>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值