Updated on
.NET has no File.Rename() method. To rename a file in C#, we move it to a new name in the same folder with File.Move() or FileInfo.MoveTo(), and to rename a folder we call Directory.Move().
We’ll find the files first, rename one, then a whole batch, then a folder, and finish with the exceptions each of those can throw.
Let’s start.
Finding Files in a Folder
Before we get into the details of renaming files in C#, it’s important to know how to locate them. We’ll start by exploring the fundamental concept of finding files within a folder.
The Directory class from the System.IO namespace provides methods we can use for retrieving a list of all the files in a folder.Â
Let’s use one of its methods to retrieve a list of files from a folder and its subfolders. We put each method in a static class, and the code that calls it in another method of the same class:
public static IEnumerable<string> FindFilesInFolder(string directoryPath)
{
return Directory.EnumerateFiles(directoryPath, "*", SearchOption.AllDirectories);
}
Our method takes a single directoryPath parameter and returns an IEnumerable<string>, which may be enumerated to retrieve a list of all the files in the specified directory and all subdirectories.
It uses the EnumerateFiles() method to get a list of all the files in the directory path.
The * wildcard character used to match any file name and the SearchOption.AllDirectories value used to specify whether or not to include subdirectories in the search can be left out, since EnumerateFiles() has overloads without them. Without the option, the search stays in the top folder.
To test our method, let’s create a directory with files dynamically:
var directoryPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(directoryPath);
for (var i = 1; i < 5; i++)
{
var filePath = Path.Combine(directoryPath, $"File{i}.txt");
File.Create(filePath).Dispose();
}
var filesInFolder = FindFilesInFolder(directoryPath);
foreach (var file in filesInFolder)
{
var fileName = Path.GetFileName(file);
Console.WriteLine(fileName);
}
Firstly, we create a random directory within the temporary directory. Next, we create four empty text files in the new directory: File1.txt, File2.txt, File3.txt, and File4.txt.
Then, we assign the list of files returned by the static FindFilesInFolder() method to the filesInFolder variable.
Lastly, our foreach loop iterates over the list of files and gets the file names with Path.GetFileName(), and displays them on the console:
File1.txt File2.txt File3.txt File4.txt
How Do We Rename a Single File in C#?
.NET has no File.Rename() method. A rename is a move that keeps the file in the same folder, so we call File.Move(oldPath, newPath) and put the new name in the new path.
FileInfo.MoveTo(newPath) does the same job from an object. We create a FileInfo for the file, call MoveTo(), and from then on that object points at the renamed file.
Both methods take full or relative paths. A relative path is resolved against the current working directory, so passing only a file name as the destination moves the file into whatever folder our app runs from.
If a file with the new name already exists, the move throws an IOException. Since .NET Core 3.0, File.Move(oldPath, newPath, overwrite: true) replaces that file instead.
Renaming a file to its own name does nothing and throws nothing. A case-only rename, such as readme.txt to README.txt, works with a single call on .NET 10.
If replacing the existing file is what we want, we compare the options in different ways to overwrite a file in C#.
Rename Files Using File Class
The File class is a static class that provides methods for common file operations, including renaming files.
Let’s rename a file using the File class:
public static void RenameFileWithFileClass(string oldFile, string newFile)
{
File.Move(oldFile, newFile);
}
Here, our method takes two parameters, oldFile representing the file we wish to rename and newFile indicating the desired new file name.
Then we invoke the File.Move() method to rename the file.
Now, let’s use our RenameFileWithFileClass() method:
var directoryPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(directoryPath);
var oldFile = Path.Combine(directoryPath, "File1.txt");
File.Create(oldFile).Dispose();
var newFile = Path.Combine(directoryPath, "File_v1.txt");
RenameFileWithFileClass(oldFile, newFile);
Console.WriteLine($"Renamed {Path.GetFileName(oldFile)} to {Path.GetFileName(newFile)}");
We create a temporary directory and store it in the directoryPath variable, and then create a file named File1.txt within it, and store it in the oldFile variable.
Next, we specify the new file name in the newFile variable and call our method to rename the file.
The console confirms the rename:
Renamed File1.txt to File_v1.txt
Rename Files Using FileInfo Class
Unlike the File class, the FileInfo class is a non-static class that provides properties and methods for manipulating files. It also provides us with a method for renaming a file.
Let’s rename a file using the FileInfo class:
public static void RenameFileWithFileInfoClass(string oldFile, string newFile)
{
var file = new FileInfo(oldFile);
file.MoveTo(newFile);
}
In this example, our method takes the full path to the old file and the new file as parameters.
It creates a new FileInfo object for the old file and assigns it to the file variable, and then calls MoveTo() to move the old file to the new location (in other words, to rename the file).
Let’s see our RenameFileWithFileInfoClass() method in action:
var directoryPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(directoryPath);
var oldFile = Path.Combine(directoryPath, "File2.txt");
File.Create(oldFile).Dispose();
var newFile = Path.Combine(directoryPath, "File_v2.txt");
RenameFileWithFileInfoClass(oldFile, newFile);
Console.WriteLine($"Renamed {Path.GetFileName(oldFile)} to {Path.GetFileName(newFile)}");
Here, we also create a temporary directory and store it in the directoryPath variable, and then create a file named File2.txt within it, and store it in the oldFile variable.
Next, we specify the new file name in the newFile variable and call our method to rename the file.
The console message verifies the successful execution:
Renamed File2.txt to File_v2.txt
Which Method Should We Use?
While both methods achieve the same goal of changing a file name, they differ in their implementation and suitability for specific scenarios.
The File.Move() method is a concise and efficient option for renaming a single file, as it requires only the source file’s path and destination path, making it a straightforward choice for one-off renaming tasks.
FileInfo.MoveTo() pays off when we already hold a FileInfo, or want to keep working with the file after the rename. The method updates the object itself, so Name and FullName describe the renamed file straight after the call:
File.Create(Path.Combine(directoryPath, "report.txt")).Dispose(); var file = new FileInfo(Path.Combine(directoryPath, "report.txt")); file.MoveTo(Path.Combine(directoryPath, "report-final.txt")); Console.WriteLine(file.Name);
The console shows the new name:
report-final.txt
Older advice prefers FileInfo because it skips repeated security checks. Those checks belonged to .NET Framework’s Code Access Security, which .NET Core and later versions don’t enforce, so on .NET 10 we pick by convenience and not by speed.
For a one-off rename, File.Move() is shorter. When we already have a FileInfo from a directory listing, MoveTo() saves us from passing its path around. We compare the two classes in more detail in File and FileInfo in C#.
How Do We Change Only the File Extension?
Changing an extension is a rename too. Path.ChangeExtension() builds the new path, and File.Move() does the rename:
public static string ChangeExtension(string filePath, string newExtension)
{
var newFilePath = Path.ChangeExtension(filePath, newExtension);
File.Move(filePath, newFilePath);
return newFilePath;
}
Called with a path to notes.txt and ".md", it leaves notes.md in the same folder and returns its path.
Path.ChangeExtension() only works on the string. It doesn’t look at the disk, so without the File.Move() call nothing gets renamed. We cover the rest of its helpers in our article on the Path class in C#.
Batch Rename Files
Batch renaming is a great way to change the names of multiple files at once. It can save us a lot of time, especially if we have many files to rename. It can also help us ensure that our file names are consistent and accurate.
Let’s batch-rename image files with date and time. First, let’s do it using the File class:
public static void RenameImagesWithDateTime(string directoryPath)
{
var allowedExtensions = new[] { ".jpg", ".png", ".jpeg", ".gif" };
var imageFiles = Directory.EnumerateFiles(directoryPath)
.Where(file => allowedExtensions.Contains(Path.GetExtension(file),
StringComparer.OrdinalIgnoreCase));
foreach (var imageFile in imageFiles)
{
var creationTime = File.GetCreationTime(imageFile);
var fileExtension = Path.GetExtension(imageFile);
var baseName = $"Image_{creationTime:yyyy-MM-dd_HHmmss}";
var newFilePath = Path.Combine(directoryPath, $"{baseName}{fileExtension}");
for (var copy = 1; File.Exists(newFilePath) && newFilePath != imageFile; copy++)
{
newFilePath = Path.Combine(directoryPath, $"{baseName}_{copy}{fileExtension}");
}
File.Move(imageFile, newFilePath);
}
}
This method takes a directory path to enumerate and filters the results to only include images with the following extensions: .jpg, .png, .jpeg, and .gif. The filtered files are then stored in the imageFiles variable.
Thereafter, we iterate over the filtered files, extracting their creation times and file extensions. Next, we create new file names, prefixed with Image_ and the file creation time in yyyy-MM-dd_HHmmss format.
Before we move anything, we check whether that name is free. Files copied or downloaded together can share the same creation second, so two images can end up wanting the same new name. File.Move() throws an IOException when the destination exists, and the folder would be left half renamed. When the name is taken, the for loop adds _1, _2 and so on until it finds one that isn’t.
The newFilePath != imageFile check stops the loop when the free name is the file’s own name. Thanks to it, running the method a second time on the same folder changes nothing.
Finally, we rename the file with the File.Move() method.
Let’s run the method to batch-rename our image files:
var directoryPath = Path.Combine(Path.GetTempPath(), "MyImages"); RenameImagesWithDateTime(directoryPath);
We provide the full directory path to the images we want to rename and pass it to the RenameImagesWithDateTime() method to rename our files.
Now, let’s update the method to use the FileInfo class. We just need to update the foreach loop code:
foreach (var imageFile in imageFiles)
{
var file = new FileInfo(imageFile);
var creationTime = file.CreationTime;
var fileExtension = file.Extension;
var baseName = $"Image_{creationTime:yyyy-MM-dd_HHmmss}";
var newFilePath = Path.Combine(directoryPath, $"{baseName}{fileExtension}");
for (var copy = 1; File.Exists(newFilePath) && newFilePath != imageFile; copy++)
{
newFilePath = Path.Combine(directoryPath, $"{baseName}_{copy}{fileExtension}");
}
file.MoveTo(newFilePath);
}
Using the FileInfo class, we create a new object for each file, retrieve the creation time and extension, and move the old files to the new path. The name check is the same as before.
How Do We Rename a Folder in C#?
We rename a folder with Directory.Move(oldFolder, newFolder). Folders have no rename method either, so a rename is a move that keeps the folder under the same parent.
Everything inside goes along. Files, subfolders and their files all end up under the new name, and the old path is gone after the call.
DirectoryInfo.MoveTo() is the instance version. It updates its DirectoryInfo object the same way FileInfo.MoveTo() does.
Directory.Move() throws an IOException in three common cases: a folder with the new name already exists, the destination is on another drive, or, on Windows, a file inside the folder is open in another process. There is no overwrite flag, and the method won’t copy across drives the way File.Move() does. Moving a folder to another drive means copying it and deleting the original ourselves.
A case-only rename, such as photos to Photos, worked with one call in our test on .NET 10.
Let’s rename a folder that holds a subfolder and a file:
public static void RenameFolder(string oldFolder, string newFolder)
{
Directory.Move(oldFolder, newFolder);
}
Now let’s call it:
var parentPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
var oldFolder = Path.Combine(parentPath, "Invoices2025");
Directory.CreateDirectory(Path.Combine(oldFolder, "Q1"));
File.Create(Path.Combine(oldFolder, "Q1", "invoice-001.pdf")).Dispose();
var newFolder = Path.Combine(parentPath, "Invoices-2025");
RenameFolder(oldFolder, newFolder);
Console.WriteLine($"Renamed {Path.GetFileName(oldFolder)} to {Path.GetFileName(newFolder)}");
Console.WriteLine($"Invoice moved along: {File.Exists(Path.Combine(newFolder, "Q1", "invoice-001.pdf"))}");
We create Invoices2025 with a Q1 subfolder and one empty invoice in it, then rename the folder to Invoices-2025. The second line checks that the invoice now sits under the new name:
Renamed Invoices2025 to Invoices-2025 Invoice moved along: True
The Microsoft Learn page for Directory.Move() is explicit about an existing destination: “Starting with .NET Core 3.0, the Move method throws an IOException in all platforms when the destDirName already exists.” If we aren’t sure the old folder is there in the first place, we can check if a directory exists before the call.
What Can Go Wrong When We Rename a File?
The File.Move() documentation lists several exceptions. Five of them come from the file system, not from bad arguments, and each points at a different cause.
IOException covers the most causes. The new name is already taken, the file is open in another process (on Windows), or a copy across drives failed partway. With the file held open, our test got “The process cannot access the file because it is being used by another process.”
FileNotFoundException means the source file isn’t there. DirectoryNotFoundException means a folder in the destination path doesn’t exist, and File.Move() won’t create a missing destination folder for us.
UnauthorizedAccessException means we don’t have permission to change the file or the folder it sits in.
PathTooLongException shows up when a path is longer than the system allows.
Renaming to the file’s own name is safe. Microsoft Learn’s File.Move() page says the method “does not throw an exception if the source and destination are the same.”
We catch the case we can do something about, and let the rest reach the caller:
try
{
File.Move(oldFile, newFile);
}
catch (IOException) when (File.Exists(newFile))
{
Console.WriteLine($"{Path.GetFileName(newFile)} already exists, skipping.");
}
The when filter makes sure we only swallow the exception when the new name is taken. If the name is free, a locked file or a failed copy still throws, and that’s an error we want to see. If the file might be locked by another program, we can check if a file is in use first, and for the wider picture there’s our article on exception handling in C#.
Conclusion
We’ve seen that every rename in C# is a move. File.Move() and FileInfo.MoveTo() rename a file, Path.ChangeExtension() builds the path when only the extension changes, and Directory.Move() renames a whole folder with everything in it.
For batch renames, checking that the new name is free before each move keeps one collision from stopping the whole run. If you have a renaming scheme that worked well for you, we’d like to hear about it in the comments.
Tested with .NET 10.0.10 and xUnit 2.9.3.
