1

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?

3
  • It could be that those dirty names damage your execution. Most important give us Exception message you get. Commented Jun 30, 2010 at 13:20
  • Did you debug your code to narrow down where your problem is exactly? Commented Jun 30, 2010 at 13:21
  • I made an edit to this--i figured out why my code wasn't stepping through to the 2nd foreach loop. However, would you know how to replace the invalid char with a different unique character every time so that each filename remains unique? Commented Jun 30, 2010 at 13:26

4 Answers 4

1

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...
}
Sign up to request clarification or add additional context in comments.

1 Comment

how would i append a digit to the end of the file name (with a different # everytime?)
1

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.

3 Comments

i can't quite to that to all the files -- basically my app is recursing through legal docs, so the names have to stay as close to the original as possible. however, this might be a great way to make duplicate names unique in my 2nd foreach loop!
well can always strip off the timestamp from the end of filename before the use the file thus you'll get the original file name back. eg: text_123456789.txt explode('_' , text_123456789.txt) will give you text and explode('.' , text_123456789.txt) will give you txt
better idea is prepend the timestamp (eg: 123456789_text.txt) then explode to get the file name whenever required
1

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?

1 Comment

ah, this sounds like a great idea--however i'm not quite sure how to implement. I'm very new to C#!!
1

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;            
    }
}

1 Comment

+1: thank you--i'm definitely referring to this for future reference!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.