写在前面
最近在弄一个文件传输的一个东东,在接收文件的时候,如果文件已经存在,该如何处理?提示?删除?感觉直接删除实在不太合适,万一这个文件对用户来说很重要,你给他删除了肯定不行。然后就想到了,windows系统在新建文件的时候,如果文件存在就以(n)这样的形式创建。当时觉得这种方式确实不错,查找了windows的api,未果,然后就想如果让自己实现,该如何去实现?
工具类
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Linq;
5 using System.Text;
6 using System.Text.RegularExpressions;
7 using System.Threading.Tasks;
8
9 namespace Wolfy.SaveAs
10 {
11 /// <summary>
12 /// 重命名辅助类
13 /// </summary>
14 public class ReNameHelper
15 {
16 /// <summary>
17 /// 保存同名文件时,进行重命名操作.
18 /// 例如文件夹内已存在1.txt,则再次保存时保存为1(1).txt,....1(n).txt
19 /// </summary>
20 /// <param name="strFolderPath">保存的目录</param>
21 /// <param name="strFileName">文件名</param>
22 /// <returns>新的文件名</returns>
23 public static string ReFileName(string strFolderPath, string strFileName)
24 {
25 //当前传进的文件名自带的索引
26 int intCurrentFileIndex = 0;
27 string strNewName = string.Empty;
28 //用来保存当前目录下的文件的最大索引。
29 int intMaxIndex = 0;
30 //如果文件不存在,直接返回
31 if (!File.Exists(Path.Combine(strFolderPath, strFileName)))
32 {
33 return strFileName;
34 }
35 //根据传进来的文件名,获取扩展名
36 string strExtention = Path.GetExtension(strFileName);
37 string strFileNameWithoutExtion = Path.GetFileNameWithoutExtension(strFileName);
38 //如果文件名中本身就包括括号,则需要还原原来的文件名
39 string strNameContainsBracketsRegex = "(?<fileName>.+?)" + "([((](?<fileNameIndex>\\d+)[))])" + strExtention;
40 Regex regexContain = new Regex(strNameContainsBracketsRegex, RegexOptions.Singleline);
41 if (regexContain.IsMatch(strFileName))
42 {
43 Match match = regexContain.Match(strFileName);
44 strFileNameWithoutExtion = match.Groups["fileName"].Value;
45 intCurrentFileIndex = Convert.ToInt32(match.Groups["fileNameIndex"].Value);
46 }
47 //根据传进来的文件名,通过正则匹配,找到类似的文件名,不区别中英文的括号并且括号及索引可有可无
48 string strRegex = strFileNameWithoutExtion + "([((](?<fileNameIndex>\\d+)[))])" + strExtention;
49 Regex regex = new Regex(strRegex, RegexOptions.Singleline);
50 string[] strFileNames = Directory.GetFiles(strFolderPath, "*" + strExtention)
51 .Where(x => regex.IsMatch(x) || x.Contains(strFileNameWithoutExtion))
52 .ToArray();
53 if (strFileNames != null && strFileNames.Length > 0)
54 {
55 foreach (string item in strFileNames)
56 {
57 //因为获得的文件路径数组中都是匹配成功的路径,此处不再进行判断是否匹配
58 Match match = regex.Match(item);
59 //获得索引
60 string strIndex = match.Groups["fileNameIndex"].Value;
61 //如果为空,说明只有类似 1.txt这样的文件,则返回的文件就是1(1).txt
62 //否则找到最大索引,然后拼接最大索引加一的文件名
63 if (!string.IsNullOrEmpty(strIndex))
64 {
65 int intIndex = Convert.ToInt32(strIndex);
66 if (intMaxIndex < intIndex)
67 {
68 intMaxIndex = intIndex;
69 }
70 }
71 }
72 //如果目录中存在的文件索引大于或者等于当前传进来的文件的索引则使用新的名称,否则将返回传进来的文件名称
73 if (intMaxIndex >= intCurrentFileIndex)
74 {
75 //循环接收,求出了最大的索引,则新文件的索引就是最大索引加一
76 StringBuilder sb = new StringBuilder();
77 sb.Append(strFileNameWithoutExtion);
78 sb.Append("(");
79 sb.Append((intMaxIndex + 1).ToString());
80 sb.Append(")");
81 sb.Append(strExtention);
82 strNewName = sb.ToString();
83 }
84 else
85 {
86 strNewName = strFileName;
87 }
88 }
89 else
90 {
91 //如果没有匹配到相似的文件名结构,则说明是一个新的文件,则不做任何操作
92 strNewName = strFileName;
93 }
94 return strNewName;
95 }
96 /// <summary>
97 /// 保存同名文件夹时,进行重命名操作.
98 /// 例如文件夹内已存在1的文件夹,则再次保存时保存为1(1),....1(n)
99 /// </summary>
100 /// <param name="strFolderPath">保存的目录</param>
101 /// <param name="strFolderPath">保存的目录</param>
102 /// <returns>新的目录名</returns>
103 public static string ReFolderName(string strFolderPath, string strFolderName)
104 {
105 //当前传进的文件夹自带的索引
106 int intCurrentFolderIndex = 0;
107 string strNewName = string.Empty;
108 //原始名字
109 string strOriginalName = strFolderName;
110 //用来保存当前目录下的文件的最大索引。
111 int intMaxIndex = 0;
112 if (!Directory.Exists(Path.Combine(strFolderPath, strFolderName)))
113 {
114 return strFolderName;
115 }
116 //根据传进来的文件名,通过正则匹配,找到文件夹是否已经带有索引。
117 string strRegex = "(?<folderName>.+?)([((](?<folderIndex>\\d+)[))])";
118 Regex regex = new Regex(strRegex, RegexOptions.Singleline);
119 if (regex.IsMatch(strFolderName))
120 {
121 Match match = regex.Match(strFolderName);
122 string strFolderIndex = match.Groups["folderIndex"].Value;
123 if (!string.IsNullOrEmpty(strFolderIndex))
124 {
125 intCurrentFolderIndex = Convert.ToInt32(strFolderIndex);
126 strOriginalName = match.Groups["folderName"].Value;
127 }
128 }
129
130 string[] strFolderNames = Directory.GetDirectories(strFolderPath)
131 .Where(x => regex.IsMatch(x))
132 .Select(x => x.Split(new char[] { '\\' })
133 .LastOrDefault())
134 .ToArray();
135 if (strFolderNames != null && strFolderNames.Length > 0)
136 {
137 foreach (string item in strFolderNames)
138 {
139 //因为获得的文件路径数组中都是匹配成功的路径,此处不再进行判断是否匹配
140 Match match = regex.Match(item);
141 //获得索引
142 string strIndex = match.Groups["folderIndex"].Value;
143 //如果为空,说明只有类似 1.txt这样的文件,则返回的文件就是1(1).txt
144 //否则找到最大索引,然后拼接最大索引加一的文件名
145 if (!string.IsNullOrEmpty(strIndex))
146 {
147 int intIndex = Convert.ToInt32(strIndex);
148 if (intMaxIndex < intIndex)
149 {
150 intMaxIndex = intIndex;
151 }
152 }
153 }
154 //如果目录中存在的文件索引大于或者等于当前传进来的文件的索引则使用新的名称,否则将返回传进来的文件名称
155 if (intMaxIndex >= intCurrentFolderIndex)
156 {
157 //循环接收,求出了最大的索引,则新文件的索引就是最大索引加一
158 StringBuilder sb = new StringBuilder();
159 sb.Append(strOriginalName);
160 sb.Append("(");
161 sb.Append((intMaxIndex + 1).ToString());
162 sb.Append(")");
163 strNewName = sb.ToString();
164 }
165 else
166 {
167 strNewName = strFolderName;
168 }
169 }
170 else
171 {
172 //如果没有匹配到相似的文件名结构,则说明是一个新的文件,则不做任何操作
173 strNewName = strFolderName;
174 }
175 return strNewName;
176 }
177 }
178 }
测试
测试用的保存的目录,结构如下:
测试
如果接收的文件为1.txt,则获取到的新文件名1(2).txt,因为与1.txt名称相似的文件已经存在的最大文件索引为1.
如果接收的文件夹名称为新建文件夹,则获取到的新文件夹名为新建文件夹(3),因为与新建文件夹名称相似的文件夹的最大索引为2。
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 string newName =ReNameHelper.ReFileName(@"C:\Users\Wolfy\Desktop\Test", "1.txt");
6 string strNewFolderName = ReNameHelper.ReFolderName(@"C:\Users\Wolfy\Desktop\Test\", "新建文件夹");
7 Console.WriteLine(newName);
8 Console.WriteLine(strNewFolderName);
9 Console.ReadKey();
10 }
11 }
测试结果
如果接收的文件为1(1).txt,则获取到的新文件名1(2).txt,因为与1(1).txt名称相似的文件已经存在的最大文件索引为1.
如果接收的文件夹名称为新建文件夹(1),则获取到的新文件夹名为新建文件夹(3),因为与新建文件夹名称相似的文件夹的最大索引为2。
测试结果
如果接收的文件为1(2).txt,则获取到的新文件名1(2).txt,因为与1.txt名称相似的文件已经存在的最大文件索引为1.(传进来的文件名中带的索引大于已经存在的索引)
如果接收的文件夹名称为新建文件夹(1),则获取到的新文件夹名为新建文件夹(3),因为与新建文件夹名称相似的文件夹的最大索引为2(这里在调用该方法的时候,可以首先判断一下该目录是否存在,如果不存在,直接创建不再走该方法,那么保存的文件名为:新建文件夹(1))。
如果接收的文件夹名称为新建文件夹(3),索引大于已经存在的文件夹的最大索引,则保存为新建文件夹(3)
这里只对文件名为1(1)(1).txt的做了处理,文件夹的以类似新建文件夹(n)这样的名称为主。
1 static void Main(string[] args)
2 {
3 string newName = ReNameHelper.ReFileName(@"C:\Users\Wolfy\Desktop\Test", "1(1)(2).txt");
4 string strNewFolderName = ReNameHelper.ReFolderName(@"C:\Users\Wolfy\Desktop\Test\", "新建文件夹 (2) (1)");
5 Console.WriteLine(newName);
6 Console.WriteLine(strNewFolderName);
7 Console.ReadKey();
8 }
如果test目录下已经存在:1(1)(2).txt和新建文件夹 (2) (1),则返回的结果
总结
这个类确实解决了一些问题,但是针对一些恶意输入的文件或者文件夹名也是没办法的,只能在调用重命名方法之前再加上一个判断文件或者目录是否存在的情况,如果存在再走重命名方法,如果不存在则直接保存就行。
如果您有更好的方式,请留言。
也许你会看这篇文章: