Problem with Existing File Name & Creating a Unique File Name
I have this code:
public void FileCleanup(List<string> paths)
{
string regPattern = (@"[~#&!%+{}]+");
string replacement = "";
string replacement_unique = "_";
Regex regExPattern = new Regex(regPattern);
List<string> existingNames = new List<string>();
StreamWriter errors = new StreamWriter(@"C:\Documents and Settings\jane.doe\Desktop\SharePointTesting\Errors.txt");
StreamWriter resultsofRename = new StreamWriter(@"C:\Documents and Settings\jane.doe\Desktop\SharePointTesting\Results of File Rename.txt");
foreach (string files2 in paths)
try
{
string filenameOnly = Path.GetFileName(files2);
string pathOnly = Path.GetDirectoryName(files2);
string sanitizedFileName = regExPattern.Replace(filenameOnly, replacement);
string sanitized = Path.Combine(pathOnly, sanitizedFileName);
if (!System.IO.File.Exists(sanitized))
{
existingNames.Add(sanitized);
try
{
foreach (string names in existingNames)
{
string filename = Path.GetFileName(names);
string filepath = Path.GetDirectoryName(names);
string cleanName = regExPattern.Replace(filename, replacement_unique);
string scrubbed = Path.Combine(filepath, cleanName);
System.IO.File.Move(names, scrubbed);
//resultsofRename.Write("Path: " + pathOnly + " / " + "Old File Name: " + filenameOnly + "New File Name: " + sanitized + "\r\n" + "\r\n");
resultsofRename = File.AppendText("Path: " + filepath + " / " + "Old File Name: " + filename + "New File Name: " + scrubbed + "\r\n" + "\r\n");
}
}
catch开发者_运维技巧 (Exception e)
{
errors.Write(e);
}
}
else
{
System.IO.File.Move(files2, sanitized);
resultsofRename.Write("Path: " + pathOnly + " / " + "Old File Name: " + filenameOnly + "New File Name: " + sanitized + "\r\n" + "\r\n");
}
}
catch (Exception e)
{
//write to streamwriter
}
}
}
}
What i'm trying to do here is rename "dirty" filenames by removing invalid chars (defined in the Regex), replace them with "". However, i noticed if i have duplicate file names, the app does not rename them. I.e. if i have ##test.txt and ~~test.txt in the same folder, they'd be renamed to test.txt. So, i created another foreach loop that instead replaces the invalid char with a "_" versus a blank space.
Problem is, whenever i try to run this, nothing ends up happening! None of the files are renamed!
Can someone tell me if my code is incorrect and how to fix it?
ALSO-- does anybody know how i could replace the invalid char in the 2nd foreach loop with a different char everytime? That way if there are multiple instances of i.e. %Test.txt, ~Test.txt and #test.txt (all to be renamed to test.txt), they can somehow be uniquely named with a different char?
However, would you know how to replace the invalid char with a different unique character every time so that each filename remains unique?
This is one way:
char[] uniques = ",'%".ToCharArray(); // whatever chars you want
foreach (string file in files)
{
foreach (char c in uniques)
{
string replaced = regexPattern.Replace(file, c.ToString());
if (File.Exists(replaced)) continue;
// create file
}
}
You may of course want to refactor this into its own method. Take note also that the maximum number of files only differing by unique character is limited to the number of characters in your uniques
array, so if you have a lot of files with the same name only differing by the special characters you listed, it might be wise to use a different method, such as appending a digit to the end of the file name.
how would i append a digit to the end of the file name (with a different # everytime?)
A slightly modified version of Josh's suggestion would work that keeps track of the modified file names mapped to the number of times the same file name has been generated after the replacement:
var filesCount = new Dictionary<string, int>();
string replaceSpecialCharsWith = "_"; // or "", whatever
foreach (string file in files)
{
string sanitizedPath = regexPattern.Replace(file, replaceSpecialCharsWith);
if (filesCount.ContainsKey(sanitizedPath))
{
filesCount[file]++;
}
else
{
filesCount.Add(sanitizedPath, 0);
}
string newFileName = String.Format("{0}{1}{2}",
Path.GetFileNameWithoutExtension(sanitizedPath),
filesCount[sanitizedPath] != 0
? filesCount[sanitizedPath].ToString()
: "",
Path.GetExtension(sanitizedPath));
string newFilePath = Path.Combine(Path.GetDirectoryName(sanitizedPath),
newFileName);
// create file...
}
just a suggestion
after removing/replacing the special characters append timestamp to the file name. timestamps are unique so appending them to filenames will give you a unique filename.
How about maintaining a dictionary of all renamed files, checking each file against it, and if already existing add a number to the end of it?
In response to the answer @Josh Smeaton's gave here's some sample code using a dictionary to keep track of the file names :-
class Program
{
private static readonly Dictionary<string,int> _fileNames = new Dictionary<string, int>();
static void Main(string[] args)
{
var fileName = GetUniqueFileName("filename.txt");
Console.WriteLine(fileName);
fileName = GetUniqueFileName("someotherfilename.txt");
Console.WriteLine(fileName);
fileName = GetUniqueFileName("filename.txt");
Console.WriteLine(fileName);
fileName = GetUniqueFileName("adifferentfilename.txt");
Console.WriteLine(fileName);
fileName = GetUniqueFileName("filename.txt");
Console.WriteLine(fileName);
fileName = GetUniqueFileName("adifferentfilename.txt");
Console.WriteLine(fileName);
Console.ReadLine();
}
private static string GetUniqueFileName(string fileName)
{
// If not already in the dictionary add it otherwise increment the counter
if (!_fileNames.ContainsKey(fileName))
_fileNames.Add(fileName, 0);
else
_fileNames[fileName] += 1;
// Now return the new name using the counter if required (0 means it's just been added)
return _fileNames[fileName].ToString().Replace("0", string.Empty) + fileName;
}
}
精彩评论