C# 如果文件已以 Windows 方式存在,则自动重命名文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13049732/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 01:28:26  来源:igfitidea点击:

Automatically rename a file if it already exists in Windows way

c#.net

提问by SKJ

My C# code is generating several text files based on input and saving those in a folder. Also, I am assuming that the name of the text file will be same as input.(The input contains only letters) If two files has same name then it is simply overwriting the previous file. But I want to keep both files.

我的 C# 代码根据输入生成几个文本文件并将它们保存在一个文件夹中。另外,我假设文本文件的名称将与输入相同。(输入仅包含字母)如果两个文件具有相同的名称,那么它只是覆盖前一个文件。但我想保留这两个文件。

I don't want to append current date time or a random number to the 2nd file name. Instead I want to do it the same way Windows does. If the fisrt file name is AAA.txt , then second file name is AAA(2).txt, third file name will be AAA(3).txt.....N th file name will be AAA(N).txt.

我不想将当前日期时间或随机数附加到第二个文件名。相反,我想像 Windows 那样做。如果第一个文件名为 AAA.txt ,则第二个文件名为 AAA(2).txt,第三个文件名为 AAA(3).txt.....N 第 N 个文件名为 AAA(N).txt .

string[] allFiles = Directory.GetFiles(folderPath).Select(filename => Path.GetFileNameWithoutExtension(filename)).ToArray();
        foreach (var item in allFiles)
        {
            //newFileName is the txt file which is going to be saved in the provided folder
            if (newFileName.Equals(item, StringComparison.InvariantCultureIgnoreCase))
            {
                // What to do here ?                
            }
        }

采纳答案by cadrell0

This will check for the existence of files with tempFileName and increment the number by one until it finds a name that does not exist in the directory.

这将检查具有 tempFileName 的文件是否存在,并将数字递增 1,直到找到目录中不存在的名称。

int count = 1;

string fileNameOnly = Path.GetFileNameWithoutExtension(fullPath);
string extension = Path.GetExtension(fullPath);
string path = Path.GetDirectoryName(fullPath);
string newFullPath = fullPath;

while(File.Exists(newFullPath)) 
{
    string tempFileName = string.Format("{0}({1})", fileNameOnly, count++);
    newFullPath = Path.Combine(path, tempFileName + extension);
}

回答by Ian

How about just:

怎么样只是:

int count = 1;
String tempFileName = newFileName;

foreach (var item in allFiles)
{
  if (tempFileName.Equals(item, StringComparison.InvariantCultureIgnoreCase))
  {
    tempFileName = String.Format("{0}({1})", newFileName, count++);
  }
}

This will use the original file name if it's not there, if not it'll take a new file name with the index in brackets (although this code isn't taking the extension into account). If the newly generated name "text(001)" is used then it'll increment until it finds a valid unused file name.

如果它不存在,这将使用原始文件名,否则它将采用一个新的文件名,括号中的索引(尽管此代码未考虑扩展名)。如果使用新生成的名称“text(001)”,那么它将递增,直到找到有效的未使用文件名。

回答by Phill

The other examples don't take into account the filename / extension.

其他示例不考虑文件名/扩展名。

Here you go:

干得好:

    public static string GetUniqueFilename(string fullPath)
    {
        if (!Path.IsPathRooted(fullPath))
            fullPath = Path.GetFullPath(fullPath);
        if (File.Exists(fullPath))
        {
            String filename = Path.GetFileName(fullPath);
            String path = fullPath.Substring(0, fullPath.Length - filename.Length);
            String filenameWOExt = Path.GetFileNameWithoutExtension(fullPath);
            String ext = Path.GetExtension(fullPath);
            int n = 1;
            do
            {
                fullPath = Path.Combine(path, String.Format("{0} ({1}){2}", filenameWOExt, (n++), ext));
            }
            while (File.Exists(fullPath));
        }
        return fullPath;
    }

回答by RePierre

You can declare a Dictionary<string,int>to keep the number of times each root file name was saved. After that, on your Savemethod, just increase the counter and append it to the base file name:

您可以声明 aDictionary<string,int>以保留每个根文件名被保存的次数。之后,在您的Save方法中,只需增加计数器并将其附加到基本文件名:

var key = fileName.ToLower();
string newFileName;
if(!_dictionary.ContainsKey(key))
{
    newFileName = fileName;
    _dictionary.Add(key,0);
}
else
{
    _dictionary[key]++;
   newFileName = String.Format("{0}({1})", fileName, _dictionary[key])
}

This way, you'll have a counter for each distinct file name: AAA(1), AAA(2); BBB(1)...

这样,您将为每个不同的文件名创建一个计数器:AAA(1), AAA(2); BBB(1)...

回答by SKJ

It's working fine now. thanks guys for the answers..

它现在工作正常。谢谢大家的回答。。

string[] allFiles = Directory.GetFiles(folderPath).Select(filename => Path.GetFileNameWithoutExtension(filename)).ToArray();
        string tempFileName = fileName;
        int count = 1;
        while (allFiles.Contains(tempFileName ))
        {
            tempFileName = String.Format("{0} ({1})", fileName, count++); 
        }

        output = Path.Combine(folderPath, tempFileName );
        string fullPath=output + ".xml";

回答by codemirror

int count= 0;

file is the name of file

文件是文件名

while (File.Exists(fullpathwithfilename))  //this will check for existence of file
{ 
// below line names new file from file.xls to file1.xls   
fullpathwithfilename= fullpathwithfilename.Replace("file.xls", "file"+count+".xls"); 

count++;
}

回答by Jaex

With this code if file name is "Test (3).txt" then it will become "Test (4).txt".

使用此代码,如果文件名是“Test (3).txt”,那么它将变成“Test (4).txt”。

public static string GetUniqueFilePath(string filePath)
{
    if (File.Exists(filePath))
    {
        string folderPath = Path.GetDirectoryName(filePath);
        string fileName = Path.GetFileNameWithoutExtension(filePath);
        string fileExtension = Path.GetExtension(filePath);
        int number = 1;

        Match regex = Regex.Match(fileName, @"^(.+) \((\d+)\)$");

        if (regex.Success)
        {
            fileName = regex.Groups[1].Value;
            number = int.Parse(regex.Groups[2].Value);
        }

        do
        {
            number++;
            string newFileName = $"{fileName} ({number}){fileExtension}";
            filePath = Path.Combine(folderPath, newFileName);
        }
        while (File.Exists(filePath));
    }

    return filePath;
}

回答by popeyevey

public static string AutoRenameFilename(FileInfo file)
    {
        var filename = file.Name.Replace(file.Extension, string.Empty);
        var dir = file.Directory.FullName;
        var ext = file.Extension;

        if (file.Exists)
        {
            int count = 0;
            string added;

            do
            {
                count++;
                added = "(" + count + ")";
            } while (File.Exists(dir + "\" + filename + " " + added + ext));

            filename += " " + added;
        }

        return (dir + filename + ext);
    }

回答by Evdzhan Mustafa

I was looking for a solution that would move a file, and make sure that if the destination file name is not already taken. It would follow the same logic as Windows and append a number, with brackets after the duplicate file.

我正在寻找一种可以移动文件的解决方案,并确保目标文件名尚未被采用。它将遵循与 Windows 相同的逻辑并附加一个数字,并在重复文件后使用方括号。

The top answer, thanks to @cadrell0, helped me arrive to the following solution:

感谢@cadrell0,最佳答案帮助我找到了以下解决方案:

    /// <summary>
    /// Generates full file path for a file that is to be moved to a destinationFolderDir. 
    /// 
    /// This method takes into account the possiblity of the file already existing, 
    /// and will append number surrounded with brackets to the file name.
    /// 
    /// E.g. if D:\DestinationDir contains file name file.txt,
    /// and your fileToMoveFullPath is D:\Source\file.txt, the generated path will be D:\DestinationDir\file(1).txt
    /// 
    /// </summary>
    /// <param name="destinationFolderDir">E.g. D:\DestinationDir </param>
    /// <param name="fileToMoveFullPath">D:\Source\file.txt</param>
    /// <returns></returns>
    public string GetFullFilePathWithDuplicatesTakenInMind(string destinationFolderDir, string fileToMoveFullPath)
    {
        string destinationPathWithDuplicatesTakenInMind;

        string fileNameWithExtension = Path.GetFileName(fileToMoveFullPath);
        string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileToMoveFullPath);
        string fileNameExtension = Path.GetExtension(fileToMoveFullPath);

        destinationPathWithDuplicatesTakenInMind = Path.Combine(destinationFolderDir, fileNameWithExtension);

        int count = 0;
        while (File.Exists(destinationPathWithDuplicatesTakenInMind))
        {
            destinationPathWithDuplicatesTakenInMind = Path.Combine(destinationFolderDir, $"{fileNameWithoutExtension}({count}){fileNameExtension}");
            count = count + 1; // sorry, not a fan of the ++ operator.
        }

        return destinationPathWithDuplicatesTakenInMind;
    }

回答by Rupert

With regard to Giuseppe's comment on the way windows renames files I worked on a version that finds any existing index i.e. (2) in the file name and renames the file as per windows accordingly. The sourceFileName is assumed to be valid and the user is assumed to have write permission on the destination folder by this point:

关于 Giuseppe 对 windows 重命名文件方式的评论,我在一个版本上工作,该版本在文件名中找到任何现有索引,即 (2),并相应地根据 windows 重命名文件。假定 sourceFileName 是有效的,并且此时假定用户对目标文件夹具有写权限:

using System.IO;
using System.Text.RegularExpressions;

    private void RenameDiskFileToMSUnique(string sourceFileName)
    {
        string destFileName = "";
        long n = 1;
        // ensure the full path is qualified
        if (!Path.IsPathRooted(sourceFileName)) { sourceFileName = Path.GetFullPath(sourceFileName); }

        string filepath = Path.GetDirectoryName(sourceFileName);
        string fileNameWOExt = Path.GetFileNameWithoutExtension(sourceFileName);
        string fileNameSuffix = "";
        string fileNameExt = Path.GetExtension(sourceFileName);
        // if the name includes the text "(0-9)" then we have a filename, instance number and suffix  
        Regex r = new Regex(@"\(\d+\)");
        Match match = r.Match(fileNameWOExt);
        if (match.Success) // the pattern (0-9) was found
        {
            // text after the match
            if (fileNameWOExt.Length > match.Index + match.Length) // remove the format and create the suffix
            {
                fileNameSuffix = fileNameWOExt.Substring(match.Index + match.Length, fileNameWOExt.Length - (match.Index + match.Length));
                fileNameWOExt = fileNameWOExt.Substring(0, match.Index);
            }
            else // remove the format at the end
            {
                fileNameWOExt = fileNameWOExt.Substring(0, fileNameWOExt.Length - match.Length);
            }
            // increment the numeric in the name
            n = Convert.ToInt64(match.Value.Substring(1, match.Length - 2)) + 1;
        }
        // format variation: indexed text retains the original layout, new suffixed text inserts a space!
        do
        {
            if (match.Success) // the text was already indexed
            {
                if (fileNameSuffix.Length > 0)
                {
                    destFileName = Path.Combine(filepath, String.Format("{0}({1}){2}{3}", fileNameWOExt, (n++), fileNameSuffix, fileNameExt));
                }
                else
                {
                    destFileName = Path.Combine(filepath, String.Format("{0}({1}){2}", fileNameWOExt, (n++), fileNameExt));
                }
            }
            else // we are adding a new index
            {
                destFileName = Path.Combine(filepath, String.Format("{0} ({1}){2}", fileNameWOExt, (n++), fileNameExt));
            }
        }
        while (File.Exists(destFileName));

        File.Copy(sourceFileName, destFileName);
    }