项目调试之小工具---文件名替换
效果图:
一款可圈可点的改名小工具设计实现还是不错的,主要实现代码如下:
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); } } } } }
广积粮,筑高墙,缓称王