C#: Renaming files on the result of `Directory.EnumerateFiles` causes infinite loop

162 Views Asked by At

I have a folder contains a lot of files(>100000), and I want to write some code to perform a batch renaming. I use Directory.EnumerateFiles rather than Directory.GetFiles since the former does not allocate the space for all the files name so I don't need to be worried about the memory. Here is the code:

var files = Directory.EnumerateFiles(@"C:\many_files");
foreach (var file in files)
{
    // Use`File.Move` to do the renaming stuff
}

However I encountered an infinite loop. That's because EnumerateFiles is executing along with the renaming action. So after renaming a file, the file might be reordered to the end of the "enumeration list" and EnumerateFiles will return it again.

So Is there a solution? Or I have to use the GetFiles which may cause OOM.

1

There are 1 best solutions below

5
Zee On

The easiest way to do this is to load all the filePaths in memory and rename them.

Since you're worried about memory, You can do this: Provided there wouldn't be any additions to the directory during this process.

static void Rename(string path, int batchSize = 5)
{
    var queryable = Directory.EnumerateFiles(path).AsQueryable(); //Queryable For Getting Files

    var totalFiles = queryable.Count(); //Get Total File Count in Path

    int count = 0;//counter

    while (count <= totalFiles)
    {
        var filesToProcess = queryable
                            .Where(f => !Path.GetFileName(f).StartsWith("reviewed_")) //Get Files Without this prefix
                            .Skip(count)
                            .Take(batchSize)
                            .ToList();//Get Batch To Process

        foreach (var file in filesToProcess)
        {
            //Do Renaming Stuff
            Console.WriteLine(file);
        }

        count += batchSize;
    }
}