写在前面

最近在弄一个文件传输的一个东东,在接收文件的时候,如果文件已经存在,该如何处理?提示?删除?感觉直接删除实在不太合适,万一这个文件对用户来说很重要,你给他删除了肯定不行。然后就想到了,windows系统在新建文件的时候,如果文件存在就以(n)这样的形式创建。当时觉得这种方式确实不错,查找了windows的api,未果,然后就想如果让自己实现,该如何去实现?

工具类

 using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks; namespace Wolfy.SaveAs
{
/// <summary>
/// 重命名辅助类
/// </summary>
public class ReNameHelper
{
/// <summary>
/// 保存同名文件时,进行重命名操作.
/// 例如文件夹内已存在1.txt,则再次保存时保存为1(1).txt,....1(n).txt
/// </summary>
/// <param name="strFolderPath">保存的目录</param>
/// <param name="strFileName">文件名</param>
/// <returns>新的文件名</returns>
public static string ReFileName(string strFolderPath, string strFileName)
{
//当前传进的文件名自带的索引
int intCurrentFileIndex = ;
string strNewName = string.Empty;
//用来保存当前目录下的文件的最大索引。
int intMaxIndex = ;
//如果文件不存在,直接返回
if (!File.Exists(Path.Combine(strFolderPath, strFileName)))
{
return strFileName;
}
//根据传进来的文件名,获取扩展名
string strExtention = Path.GetExtension(strFileName);
string strFileNameWithoutExtion = Path.GetFileNameWithoutExtension(strFileName);
//如果文件名中本身就包括括号,则需要还原原来的文件名
string strNameContainsBracketsRegex = "(?<fileName>.+?)" + "([((](?<fileNameIndex>\\d+)[))])" + strExtention;
Regex regexContain = new Regex(strNameContainsBracketsRegex, RegexOptions.Singleline);
if (regexContain.IsMatch(strFileName))
{
Match match = regexContain.Match(strFileName);
strFileNameWithoutExtion = match.Groups["fileName"].Value;
intCurrentFileIndex = Convert.ToInt32(match.Groups["fileNameIndex"].Value);
}
//根据传进来的文件名,通过正则匹配,找到类似的文件名,不区别中英文的括号并且括号及索引可有可无
string strRegex = strFileNameWithoutExtion + "([((](?<fileNameIndex>\\d+)[))])" + strExtention;
Regex regex = new Regex(strRegex, RegexOptions.Singleline);
string[] strFileNames = Directory.GetFiles(strFolderPath, "*" + strExtention)
.Where(x => regex.IsMatch(x) || x.Contains(strFileNameWithoutExtion))
.ToArray();
if (strFileNames != null && strFileNames.Length > )
{
foreach (string item in strFileNames)
{
//因为获得的文件路径数组中都是匹配成功的路径,此处不再进行判断是否匹配
Match match = regex.Match(item);
//获得索引
string strIndex = match.Groups["fileNameIndex"].Value;
//如果为空,说明只有类似 1.txt这样的文件,则返回的文件就是1(1).txt
//否则找到最大索引,然后拼接最大索引加一的文件名
if (!string.IsNullOrEmpty(strIndex))
{
int intIndex = Convert.ToInt32(strIndex);
if (intMaxIndex < intIndex)
{
intMaxIndex = intIndex;
}
}
}
//如果目录中存在的文件索引大于或者等于当前传进来的文件的索引则使用新的名称,否则将返回传进来的文件名称
if (intMaxIndex >= intCurrentFileIndex)
{
//循环接收,求出了最大的索引,则新文件的索引就是最大索引加一
StringBuilder sb = new StringBuilder();
sb.Append(strFileNameWithoutExtion);
sb.Append("(");
sb.Append((intMaxIndex + ).ToString());
sb.Append(")");
sb.Append(strExtention);
strNewName = sb.ToString();
}
else
{
strNewName = strFileName;
}
}
else
{
//如果没有匹配到相似的文件名结构,则说明是一个新的文件,则不做任何操作
strNewName = strFileName;
}
return strNewName;
}
/// <summary>
/// 保存同名文件夹时,进行重命名操作.
/// 例如文件夹内已存在1的文件夹,则再次保存时保存为1(1),....1(n)
/// </summary>
/// <param name="strFolderPath">保存的目录</param>
/// <param name="strFolderPath">保存的目录</param>
/// <returns>新的目录名</returns>
public static string ReFolderName(string strFolderPath, string strFolderName)
{
//当前传进的文件夹自带的索引
int intCurrentFolderIndex = ;
string strNewName = string.Empty;
//原始名字
string strOriginalName = strFolderName;
//用来保存当前目录下的文件的最大索引。
int intMaxIndex = ;
if (!Directory.Exists(Path.Combine(strFolderPath, strFolderName)))
{
return strFolderName;
}
//根据传进来的文件名,通过正则匹配,找到文件夹是否已经带有索引。
string strRegex = "(?<folderName>.+?)([((](?<folderIndex>\\d+)[))])";
Regex regex = new Regex(strRegex, RegexOptions.Singleline);
if (regex.IsMatch(strFolderName))
{
Match match = regex.Match(strFolderName);
string strFolderIndex = match.Groups["folderIndex"].Value;
if (!string.IsNullOrEmpty(strFolderIndex))
{
intCurrentFolderIndex = Convert.ToInt32(strFolderIndex);
strOriginalName = match.Groups["folderName"].Value;
}
} string[] strFolderNames = Directory.GetDirectories(strFolderPath)
.Where(x => regex.IsMatch(x))
.Select(x => x.Split(new char[] { '\\' })
.LastOrDefault())
.ToArray();
if (strFolderNames != null && strFolderNames.Length > )
{
foreach (string item in strFolderNames)
{
//因为获得的文件路径数组中都是匹配成功的路径,此处不再进行判断是否匹配
Match match = regex.Match(item);
//获得索引
string strIndex = match.Groups["folderIndex"].Value;
//如果为空,说明只有类似 1.txt这样的文件,则返回的文件就是1(1).txt
//否则找到最大索引,然后拼接最大索引加一的文件名
if (!string.IsNullOrEmpty(strIndex))
{
int intIndex = Convert.ToInt32(strIndex);
if (intMaxIndex < intIndex)
{
intMaxIndex = intIndex;
}
}
}
//如果目录中存在的文件索引大于或者等于当前传进来的文件的索引则使用新的名称,否则将返回传进来的文件名称
if (intMaxIndex >= intCurrentFolderIndex)
{
//循环接收,求出了最大的索引,则新文件的索引就是最大索引加一
StringBuilder sb = new StringBuilder();
sb.Append(strOriginalName);
sb.Append("(");
sb.Append((intMaxIndex + ).ToString());
sb.Append(")");
strNewName = sb.ToString();
}
else
{
strNewName = strFolderName;
}
}
else
{
//如果没有匹配到相似的文件名结构,则说明是一个新的文件,则不做任何操作
strNewName = strFolderName;
}
return strNewName;
}
}
}

测试

测试用的保存的目录,结构如下:

测试

如果接收的文件为1.txt,则获取到的新文件名1(2).txt,因为与1.txt名称相似的文件已经存在的最大文件索引为1.

如果接收的文件夹名称为新建文件夹,则获取到的新文件夹名为新建文件夹(3),因为与新建文件夹名称相似的文件夹的最大索引为2。

  class Program
{
static void Main(string[] args)
{
string newName =ReNameHelper.ReFileName(@"C:\Users\Wolfy\Desktop\Test", "1.txt");
string strNewFolderName = ReNameHelper.ReFolderName(@"C:\Users\Wolfy\Desktop\Test\", "新建文件夹");
Console.WriteLine(newName);
Console.WriteLine(strNewFolderName);
Console.ReadKey();
}
}

测试结果

如果接收的文件为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)这样的名称为主。

  static void Main(string[] args)
{
string newName = ReNameHelper.ReFileName(@"C:\Users\Wolfy\Desktop\Test", "1(1)(2).txt");
string strNewFolderName = ReNameHelper.ReFolderName(@"C:\Users\Wolfy\Desktop\Test\", "新建文件夹 (2) (1)");
Console.WriteLine(newName);
Console.WriteLine(strNewFolderName);
Console.ReadKey();
}

如果test目录下已经存在:1(1)(2).txt和新建文件夹 (2) (1),则返回的结果

总结

这个类确实解决了一些问题,但是针对一些恶意输入的文件或者文件夹名也是没办法的,只能在调用重命名方法之前再加上一个判断文件或者目录是否存在的情况,如果存在再走重命名方法,如果不存在则直接保存就行。

如果您有更好的方式,请留言。

也许你会看这篇文章:

[工具类]文件或文件夹xx已存在,则重命名为xx(n)(2)

[工具类]文件或文件夹xx已存在,则重命名为xx(n)的更多相关文章

  1. [工具类]文件或文件夹xx已存在,则重命名为xx(n)(2)

    写在前面 最近一直在弄文件传输组件,其中一个功能就是,在接收端接收文件时,如果文件已经存在了,则对其进行文件名+索引的方式进行自动重命名,之前也写个类似的工具类,总感觉代码太冗余,每回头想想,总觉得心 ...

  2. c#中@标志的作用 C#通过序列化实现深表复制 细说并发编程-TPL 大数据量下DataTable To List效率对比 【转载】C#工具类:实现文件操作File的工具类 异步多线程 Async .net 多线程 Thread ThreadPool Task .Net 反射学习

    c#中@标志的作用   参考微软官方文档-特殊字符@,地址 https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/toke ...

  3. Property工具类,Properties文件工具类,PropertiesUtils工具类

    Property工具类,Properties文件工具类,PropertiesUtils工具类 >>>>>>>>>>>>>& ...

  4. 【转载】 C#工具类:Csv文件转换类

    CSV是逗号分隔值格式的文件,其文件以纯文本形式存储表格数据(数字和文本).CSV文件由任意数目的记录组成,记录间以某种换行符分隔:每条记录由字段组成,字段间的分隔符是其它字符或字符串,最常见的是逗号 ...

  5. 【转载】C#工具类:实现文件操作File的工具类

    在应用程序的开发中,文件操作的使用基本上是必不可少的,FileStream类.StreamWriter类.Directory类.DirectoryInfo类等都是文件操作中时常涉及到的类,我们可以通过 ...

  6. Java常用工具类---IP工具类、File文件工具类

    package com.jarvis.base.util; import java.io.IOException;import java.io.InputStreamReader;import jav ...

  7. Java常用工具类之删除文件

    package com.wazn.learn.util; import java.io.File; /** * 删除文件工具类 * @author yangzhenyu * */ public cla ...

  8. 文件读取工具类读取properties文件

    1.创建工具类 import java.io.IOException; import java.util.Properties; /** * * 类名称:PropertiesUtil * 类描述: 文 ...

  9. java工具类获取properties文件的配置

    import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.i ...

随机推荐

  1. C++类所占内存大小计算

    C++类所占内存大小计算 说明:笔者的操作系统是32位的. class A {}; sizeof( A ) = ? sizeof( A ) = 1明明是空类,为什么编译器说它是1呢? 空类同样可以实例 ...

  2. Socket常见错误

    一.简介 本文介绍 Socket 连接常见错误.   二.常见错误 1)ECONNABORTED 描述:"software caused connection abort",即&q ...

  3. FQ 也要使用 Telegram

    不知怎么回事,一款优秀的开源,跨平台,安全的即时通讯工具 Telegram 就被 GG 了. 但是我们还得继续使用--那就 FQ 吧.用 ShadowSocks FQ 还不错. 安装 ShadowSo ...

  4. linux netstat 命令简解

    Netstat 简介: Netstat是在内核中访问网络及相关信息的程序,它能提供TCP连接,TCP和UDP监听,进程内存管理的相关报告.常见参数-a (all)显示所有选项,默认不显示LISTEN相 ...

  5. [转]VS2015 cordova尝试-camera

    本文转自:http://blog.csdn.net/greystar/article/details/47973837 1. 确保环境正常,如出现错误 ,安下载android sdk 相关版本,我在这 ...

  6. 【C#】3.算法温故而知新 - 快速排序

    快速排序相比冒泡排序,每次交换是跳跃式的.每次排序的时候设置一个基准点,将小于等于基准点的数全部放到基准点的左边,将大于等于基准点的数放到基准点的右边.这样每次交换的时候就不会像冒泡排序一样只能在相邻 ...

  7. ZOJ 1808 Immediately Decodable

    字典树较简单题,无需维护标记,注意细节即可. 代码: #include <iostream> #include <cstdio> #include <cstring> ...

  8. nginx 一二事(3) - 反向代理以及负载均衡

    先来说说正向代理 就是普通的代理,记得高中年代偷跑去网吧是要办卡的 题外话: 就是这货...相信很多80同龄人都有吧...    回到正题,那正向代理就不让你直接访问网络,而需要登录一下网吧的某个系统 ...

  9. [转]微服务(Microservice)那点事

    WHAT – 什么是微服务 微服务简介 这次参加JavaOne2015最大的困难就是听Microservice相关的session,无论内容多么水,只要题目带microservice,必定报不上名,可 ...

  10. 3D跑酷遇到的问题

    前言 项目名称:3D跑酷项目 写作目地:使用Asset Server进行多人协作开发过程中,记录遇到的问题 问题1:UIAtlas无法自动更新 描述:NGUI的Atlas图集(图片)无法自动更新 后果 ...