项目调试之小工具---文件名替换

效果图:

一款可圈可点的改名小工具设计实现还是不错的,主要实现代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace Beinet.cn.FilenameReplace
{
    public partial class MainForm : Form
    {
        /// <summary>
        /// 是否中断更名,比如正则错误时,要中断
        /// </summary>
        private bool cancel = false;
        /// <summary>
        /// 检查是否数字的正则
        /// </summary>
        Regex regNum = new Regex(@"^\d*$", RegexOptions.Compiled);

        const string chUpChar = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        /// <summary>
        /// 检查是否大写字母的正则
        /// </summary>
        Regex regUpChar = new Regex(@"^[" + chUpChar + "]*$", RegexOptions.Compiled);

        const string chLowChar = "abcdefghijklmnopqrstuvwxyz";
        /// <summary>
        /// 检查是否大写字母的正则
        /// </summary>
        Regex regLowChar = new Regex(@"^[" + chLowChar + "]*$", RegexOptions.Compiled);

        const string chNum = "零一二三四五六七八九";
        /// <summary>
        /// 检查是否中文数字的正则
        /// </summary>
        Regex regChNum = new Regex(@"^[" + chNum + "]*$", RegexOptions.Compiled);

        /// <summary>
        /// 提取旧文件名的正则
        /// </summary>
        Regex regOldName = new Regex(@"\\o(\d+)?(?:-(\d+))?", RegexOptions.Compiled);
        /// <summary>
        /// 验证文件名是否合法的正则
        /// </summary>
        Regex regValidFileName = new Regex(@"[\<\>\/\\\|\:""\*\?]", RegexOptions.Compiled);

        /// <summary>
        /// 记录上一次选中的目录
        /// </summary>
        private string lastSelectedFolder = string.Empty;


        public MainForm()
        {
            InitializeComponent();
            lstSnType.SelectedIndex = 0;
        }

        #region 按钮事件
        private int fileIdx = 1;    // 文件列表的序号 
        private SortedList<string, int> files = new SortedList<string, int>();  // 保存文件列表,因为ListView判断Contains慢,用这个代替
        // private SortedList<string, int> filenew = new SortedList<string, int>();// 保存文件新名列表
        private void btnAddFiles_Click(object sender, EventArgs e)
        {
            OpenFileDialog dialog = new OpenFileDialog { Multiselect = true };
            DialogResult result = dialog.ShowDialog();
            if (result != DialogResult.OK)
            {
                return;
            }
            foreach (var file in dialog.FileNames)
            {
                if (files.ContainsKey(file))//(ContainsFile(lvFiles, file))
                    continue;

                files.Add(file, 0);
                ListViewItem item = new ListViewItem(new[] { (fileIdx++).ToString(), file, string.Empty, string.Empty });
                lvFiles.Items.Add(item);
            }
        }

        //bool ContainsFile(ListView lv, string fileName)
        //{
        //    foreach (ListViewItem item in lv.Items)
        //    {
        //        if (item.SubItems[1].Text == fileName)
        //            return true;
        //    }
        //    return false;
        //}

        private void btnAddDir_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog dialog = new FolderBrowserDialog();
            if (!string.IsNullOrEmpty(lastSelectedFolder))
                dialog.SelectedPath = lastSelectedFolder;
            DialogResult result = dialog.ShowDialog();
            if (result != DialogResult.OK)
            {
                return;
            }
            lastSelectedFolder = dialog.SelectedPath;
            var subdir = chkSubdirs.Checked ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
            foreach (var file in Directory.GetFiles(lastSelectedFolder, "*", subdir))
            {
                if (files.ContainsKey(file))//(ContainsFile(lvFiles, file))
                    continue;

                files.Add(file, 0);

                ListViewItem item = new ListViewItem(new[] { (fileIdx++).ToString(), file, string.Empty, string.Empty });
                lvFiles.Items.Add(item);
            }
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            lvFiles.Items.Clear();
            files.Clear();
        }

        private void txtSnStep_TextChanged(object sender, EventArgs e)
        {
            TextBox txt = sender as TextBox;
            if (txt == null)
                return;
            if (!regNum.IsMatch(txt.Text))
            {
                txt.Text = Regex.Replace(txt.Text, @"[^\d]", string.Empty);
            }
        }

        private void txtSnBegin_TextChanged(object sender, EventArgs e)
        {
            TextBox txt = sender as TextBox;
            if (txt == null)
                return;

            Regex regValid;
            string regReplace;
            switch (lstSnType.Text)
            {
                //case "数字编号":
                default:
                    regValid = regNum;
                    regReplace = @"[^\d]";
                    break;
                case "大写字母":
                    regValid = regUpChar;
                    regReplace = @"[^" + chUpChar + "]";
                    break;
                case "小写字母":
                    regValid = regLowChar;
                    regReplace = @"[^" + chLowChar + "]";
                    break;
                case "汉字编号":
                    regValid = regChNum;
                    regReplace = @"[^" + chNum + "]";
                    break;
            }
            if (!regValid.IsMatch(txt.Text))
            {
                txt.Text = Regex.Replace(txt.Text, regReplace, string.Empty);
            }
        }

        private void lstSnType_SelectedIndexChanged(object sender, EventArgs e)
        {
            ComboBox lst = sender as ComboBox;
            if (lst == null)
                return;
            switch (lst.Text)
            {
                //case "数字编号":
                default:
                    txtSnBegin.Text = "1";
                    break;
                case "大写字母":
                    txtSnBegin.Text = "A";
                    break;
                case "小写字母":
                    txtSnBegin.Text = "a";
                    break;
                case "汉字编号":
                    txtSnBegin.Text = "一";
                    break;
            }
        }

        private void chkNormalAllReplace_CheckedChanged(object sender, EventArgs e)
        {
            txtNormalFrom.Enabled = !((CheckBox)sender).Checked;
        }

        private void btnHelper_Click(object sender, EventArgs e)
        {
            new HelpForm().ShowDialog();
        }

        private void btnRemoveSuccess_Click(object sender, EventArgs e)
        {
            for (int i = lvFiles.Items.Count - 1; i >= 0; i--)
            {
                if (lvFiles.Items[i].SubItems[3].Text == "成功")
                    lvFiles.Items.RemoveAt(i);
            }
        }
        #endregion


        #region 主要的按钮事件
        private void btnPreview_Click(object sender, EventArgs e)
        {
            if (lvFiles.Items.Count <= 0)
            {
                ShowMsg("请先添加文件");
                return;
            }
            lastSn = string.Empty;
            lastNum = 0;

            cancel = false;
            int idx = 0;
            int step = int.Parse(txtSnStep.Text);
            foreach (ListViewItem item in lvFiles.Items)
            {
                if (cancel)
                    break;
                string filename = item.SubItems[1].Text;
                var ret = false;
                string newName = operateName(filename, idx, ref ret);
                if (ret)
                {
                    item.SubItems[2].Text = newName;
                    item.SubItems[3].Text = string.Empty;
                    idx += step;
                }
                else
                {
                    ShowMsg(newName);
                }
            }
        }

        private void btnGo_Click(object sender, EventArgs e)
        {
            if (lvFiles.Items.Count <= 0)
            {
                ShowMsg("请先添加文件");
                return;
            }
            lastSn = string.Empty;
            lastNum = 0;

            cancel = false;
            int idx = 0;
            int step = int.Parse(txtSnStep.Text);
            int sucessCnt = 0, failCnt = 0;
            foreach (ListViewItem item in lvFiles.Items)
            {
                if (cancel)
                    break;
                string filename = item.SubItems[1].Text;
                var ret = true;
                string newName = operateName(filename, idx, ref ret);
                if (ret)
                {
                    item.SubItems[2].Text = newName;
                    item.SubItems[3].BackColor = Color.Green;
                    item.SubItems[3].Text = "成功";
                    sucessCnt++;
                }
                else
                {
                    item.SubItems[3].BackColor = Color.Red;
                    item.SubItems[3].Text = newName;
                    if (cancel)
                        ShowMsg(newName);
                    failCnt++;
                }
                idx += step;
            }
            if (chkMoveSuccess.Checked)
            {
                for (int i = lvFiles.Items.Count - 1; i >= 0; i--)
                {
                    if (lvFiles.Items[i].SubItems[3].Text == "成功")
                        lvFiles.Items.RemoveAt(i);
                }
            }
            ShowMsg("本次操作成功" + sucessCnt + "个,失败" + failCnt + "个");
        }
        #endregion


        #region 主要方法,根据配置修改文件名
        StringBuilder sbForOld = new StringBuilder();
        /// <summary>
        /// 根据配置修改文件名
        /// </summary>
        /// <param name="name"></param>
        /// <param name="idx">处理到第几个文件了</param>
        /// <param name="rename">是否执行文件重名,返回时,true表示成功,false表示失败</param>
        /// <returns></returns>
        string operateName(string name, int idx, ref bool rename)
        {
            string ret = name;
            string ext = string.Empty;
            if (chkWithExt.Checked)
            {
                ret = Path.GetFileNameWithoutExtension(ret);
                ext = Path.GetExtension(name);
            }
            else
                ret = Path.GetFileName(ret);

            // 备份旧名,后面替换\o时使用
            string old = ret;

            //if(tabReg.Focused)
            switch (tabControl1.SelectedIndex)
            {
                case 0:
                    {
                        #region 普通替换
                        string tmp = chkNormalAllReplace.Checked ? ret : txtNormalFrom.Text;
                        if(!string.IsNullOrEmpty(tmp))
                            ret = ret.Replace(tmp, txtNormalTo.Text);
                        #endregion
                    }
                    break;
                case 1:
                    {
                        #region 正则替换
                        try
                        {
                            RegexOptions opn = chkRegIgnoreCase.Checked ? RegexOptions.IgnoreCase : RegexOptions.None;
                            ret = Regex.Replace(ret, txtReg.Text, txtRegTo.Text, opn);
                        }
                        catch (Exception exp)
                        {
                            ShowMsg(exp.ToString());
                            cancel = true;
                        }

                        #endregion
                    }
                    break;
            }

            // 序号处理
            if (ret.IndexOf(@"\d") >= 0)
                ret = ret.Replace(@"\d", GetSn(idx));

            #region \o取旧文件名的字符替换处理
            Match m = regOldName.Match(ret);
            if (m.Success)
            {
                sbForOld.Length = 0;
                sbForOld.Append(ret);
                while (m.Success)
                {
                    int mI = m.Index;
                    sbForOld.Remove(mI, m.Length);// 移除匹配到的串
                    if (!m.Groups[1].Success)//m.Value == @"\o")
                    {
                        // 使用全部旧文件名
                        sbForOld.Insert(mI, old);
                    }
                    else if (m.Groups[2].Success)
                    {
                        // 使用旧文件名中的部分

                        // 交换大小
                        int i1 = int.Parse(m.Groups[1].Value);
                        int i2 = int.Parse(m.Groups[2].Value);
                        if (i1 > i2)
                        {
                            int i3 = i1;
                            i1 = i2;
                            i2 = i3;
                        }

                        // 小的位置存在才替换
                        if (i1 <= old.Length)
                        {
                            if (i2 > old.Length)
                                i2 = old.Length;
                            sbForOld.Insert(mI, old.Substring(i1 - 1, i2 - i1 + 1));
                        }
                    }
                    else
                    {
                        // 使用旧文件名中的单个字符
                        int i1 = int.Parse(m.Groups[1].Value);
                        if (i1 <= old.Length)
                            sbForOld.Insert(mI, old[i1 - 1]);
                    }
                    m = m.NextMatch();
                }
                ret = sbForOld.ToString();
            }
            #endregion

            #region 大小写处理
            if (radAllUpper.Checked)
                ret = ret.ToUpper();
            else if (radAllLower.Checked)
                ret = ret.ToLower();
            else if (radUpperFirst.Checked)
            {
                // 首字母大写,其余小写
                ret = ret.ToLower();
                ret = ret.Substring(0, 1).ToUpper() + ret.Substring(1);
            }
            else if (radRevert.Checked)
            {
                string tmp = string.Empty;
                // 反转大小写
                foreach (var c in ret)
                {
                    if (c >= 'a' && c <= 'z')
                    {
                        tmp += (char)(c - 32);
                    }
                    else if (c >= 'A' && c <= 'Z')
                    {
                        tmp += (char)(c + 32);
                    }
                    else
                        tmp += c;
                }
                ret = tmp;
            }
            else if (radAlterBig.Checked)
            {
                // 一大写一小写
                string tmp = string.Empty;
                var i = 0;
                // 反转大小写
                foreach (var c in ret)
                {
                    if (i++ % 2 == 0)
                        tmp += c.ToString().ToUpper();
                    else
                        tmp += c.ToString().ToLower();
                }
                ret = tmp;
            }
            #endregion

            ret = ret + ext;

            if (rename)
            {
                try
                {
                    string fileDir = Path.GetDirectoryName(name);
                    string newName = Path.Combine(fileDir, ret);
                    if (!File.Exists(name))
                    {
                        cancel = !chkContinue.Checked;
                        rename = false;
                        ret = "源文件不存在:" + name;
                    }
                    else if (regValidFileName.IsMatch(ret))
                    {
                        cancel = !chkContinue.Checked;
                        rename = false;
                        ret = "文件名存在非法字符:" + newName + " 旧文件名:" + name;
                    }
                    else if (File.Exists(newName))
                    {
                        if (name.Equals(newName, StringComparison.OrdinalIgnoreCase))
                        {
                            // 文件名等于自己时,先重命名为临时格式,再重命名回来,比如不改名,只是大小写替换时
                            string tmpName = Path.Combine(fileDir, Guid.NewGuid().ToString());
                            File.Move(name, tmpName);
                            File.Move(tmpName, newName);
                        }
                        else
                        {
                            cancel = !chkContinue.Checked;
                            rename = false;
                            ret = "文件已经存在:" + newName + " 旧文件名:" + name;
                        }
                    }
                    else
                        File.Move(name, newName);
                    //rename = true;// 判断为true进来的,没必要再赋值
                }
                catch (Exception exp)
                {
                    cancel = !chkContinue.Checked;
                    rename = false;
                    ret = exp.ToString();
                }
            }
            else
                rename = true;

            return ret;
        }

        #endregion

        string GetSn(int idx)
        {
            string ret = string.Empty;
            int minLen = int.Parse(txtSnBit.Text);  // 序号的最小长度
            string padleft;                         // 序号长度不足时,前面补充的字符
            string tmp = string.Empty;
            switch (lstSnType.Text)
            {
                //case "数字编号":
                default:
                    ret = (idx + int.Parse(txtSnBegin.Text)).ToString();
                    padleft = "0";
                    break;
                case "大写字母":
                    ret = AddChar(idx, txtSnBegin.Text, chUpChar);
                    padleft = "_";
                    break;
                case "小写字母":
                    ret = AddChar(idx, txtSnBegin.Text, chLowChar);
                    padleft = "_";
                    break;
                case "汉字编号":
                    foreach (var c in txtSnBegin.Text)
                    {
                        tmp += chNum.IndexOf(c);
                    }
                    idx += int.Parse(tmp);
                    foreach (var c in idx.ToString())
                    {
                        ret += chNum[int.Parse(c.ToString())];
                    }
                    padleft = "零";
                    break;
            }
            while (ret.Length < minLen)
                ret = padleft + ret;
            return ret;
        }

        private string lastSn;
        private int lastNum = 0;
        StringBuilder sbForSn = new StringBuilder();
        string AddChar(int idx, string begin, string arr)
        {
            int len = arr.Length;
            string t1 = string.IsNullOrEmpty(lastSn) ? begin : lastSn;
            sbForSn.Length = 0;
            for (var i = lastNum; i < idx; i++)
            {
                var m = t1.Length - 1;  // 从最后一个字符开始处理
                var carr = true;        // 是否进位
                while (carr && m >= 0)
                {
                    var chR = arr.IndexOf(t1[m]) + 1;
                    char chN;
                    if (chR >= len)
                    {
                        chN = arr[0];
                        //carr = true;
                    }
                    else
                    {
                        chN = arr[chR];
                        carr = false;
                    }
                    sbForSn.Insert(0, chN);
                    m--;
                }
                if (carr)
                    sbForSn.Insert(0, arr[0]);
                else if (m >= 0)
                    sbForSn.Insert(0, t1.Substring(0, m + 1));

                t1 = sbForSn.ToString();
                sbForSn.Length = 0;
            }
            lastSn = t1;
            lastNum = idx;
            return t1;
        }
        #region 51aspx下载 http://www.51aspx.com
        #endregion

        #region 右键菜单操作
        private void mnuDelSelected_Click(object sender, EventArgs e)
        {
            if (lvFiles.SelectedItems.Count <= 0)
            {
                ShowMsg("都没选择东西,你让我删啥?");
                return;
            }
            for (int i = lvFiles.SelectedItems.Count - 1; i >= 0; i--)
            {
                var item = lvFiles.SelectedItems[i];
                lvFiles.Items.Remove(item);
                files.Remove(item.SubItems[1].Text);
            }
        }

        private void mnuDelAll_Click(object sender, EventArgs e)
        {
            btnClear_Click(null, null);
        }

        private void mnuMovePrev_Click(object sender, EventArgs e)
        {
            if (lvFiles.SelectedItems.Count <= 0)
            {
                ShowMsg("都没选择东西,你让我干啥?");
                return;
            }
            var idx = lvFiles.SelectedItems[0].Index;
            //if (idx == 0)
            //{
            //    ShowMsg("已经在最前头了,我把它移哪去?");
            //    return;
            //}
            idx--;// 要上移一行,所以要减一
            var tmpArr = new List<ListViewItem>(lvFiles.SelectedItems.Count);
            foreach (ListViewItem item in lvFiles.SelectedItems)
            {
                tmpArr.Add(item);
                lvFiles.Items.RemoveAt(item.Index);
            }
            foreach (var item in tmpArr)
            {
                lvFiles.Items.Insert(idx++, item);
            }
            ReIndex(lvFiles);
            //idx--;
            //foreach (ListViewItem item in lvFiles.SelectedItems)
            ////for (int i = lvFiles.SelectedItems.Count - 1; i >= 0; i--)
            //{
            //    var tmp = item.SubItems[1].Text;
            //    item.SubItems[1].Text = lvFiles.Items[idx].SubItems[1].Text;
            //    lvFiles.Items[idx].SubItems[1].Text = tmp;
            //    idx++;
            //    //var item = lvFiles.SelectedItems[i];
            //    //lvFiles.Items.RemoveAt(item.Index);
            //    //lvFiles.Items.Insert(idx, item); // 直接Insert会导致顺序号错乱
            //}
        }

        private void mnuMoveNext_Click(object sender, EventArgs e)
        {
            if (lvFiles.SelectedItems.Count <= 0)
            {
                ShowMsg("都没选择东西,你让我干啥?");
                return;
            }
            var idx = lvFiles.SelectedItems[lvFiles.SelectedItems.Count - 1].Index;
            //if (idx == lvFiles.Items.Count - 1)
            //{
            //    ShowMsg("已经在最后头了,我把它移哪去?");
            //    return;
            //}
            idx = idx - lvFiles.SelectedItems.Count + 2;// 要下移一行,所以要加一
            var tmpArr = new List<ListViewItem>(lvFiles.SelectedItems.Count);
            foreach (ListViewItem item in lvFiles.SelectedItems)
            {
                tmpArr.Insert(0, item);
                lvFiles.Items.RemoveAt(item.Index);
            }
            foreach (var item in tmpArr)
            {
                lvFiles.Items.Insert(idx, item);
            }
            ReIndex(lvFiles);
        }

        private void mnuMoveFirst_Click(object sender, EventArgs e)
        {
            if (lvFiles.SelectedItems.Count <= 0)
            {
                ShowMsg("都没选择东西,你让我干啥?");
                return;
            }
            var idx = lvFiles.SelectedItems[0].Index;
            if (idx == 0)
            {
                ShowMsg("已经在最前头了,我把它移哪去?");
                return;
            }
            var tmpArr = new List<ListViewItem>(lvFiles.SelectedItems.Count);
            foreach (ListViewItem item in lvFiles.SelectedItems)
            {
                tmpArr.Insert(0, item);
                lvFiles.Items.RemoveAt(item.Index);
            }
            foreach (var item in tmpArr)
            {
                lvFiles.Items.Insert(0, item);
            }
            ReIndex(lvFiles);
        }

        private void mnuMoveBottom_Click(object sender, EventArgs e)
        {
            if (lvFiles.SelectedItems.Count <= 0)
            {
                ShowMsg("都没选择东西,你让我干啥?");
                return;
            }
            var idx = lvFiles.SelectedItems[lvFiles.SelectedItems.Count - 1].Index;
            if (idx == lvFiles.Items.Count - 1)
            {
                ShowMsg("已经在最后头了,我把它移哪去?");
                return;
            }
            var tmpArr = new List<ListViewItem>(lvFiles.SelectedItems.Count);
            foreach (ListViewItem item in lvFiles.SelectedItems)
            {
                tmpArr.Add(item);
                lvFiles.Items.RemoveAt(item.Index);
            }
            foreach (var item in tmpArr)
            {
                lvFiles.Items.Add(item);
            }
            ReIndex(lvFiles);
        }
        #endregion

        void ShowMsg(string msg)
        {
            MessageBox.Show(msg);
        }

        /// <summary>
        /// 重新给排序
        /// </summary>
        /// <param name="lv"></param>
        private void ReIndex(ListView lv)
        {
            var i = 1;
            foreach (ListViewItem item in lv.Items)
            {
                item.SubItems[0].Text = i++.ToString();
            }
        }

        private void lvFiles_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
            {
                for (int i = lvFiles.SelectedItems.Count - 1; i >= 0; i--)
                {
                    var item = lvFiles.SelectedItems[i];
                    lvFiles.Items.Remove(item);
                    files.Remove(item.SubItems[1].Text);
                }
            }
        }
    }
}
posted @ 2011-07-15 15:11  brainmao  阅读(550)  评论(0编辑  收藏  举报