776

How do I rename a file using C#?

default
  • 11,485
  • 9
  • 66
  • 102
Gold
  • 60,526
  • 100
  • 215
  • 315
  • 2
    I'd hate to add that there is a problem here all the solutions here especially if you do compares and are moving the file from one location to another (directory as well as filename) insofar as you should be aware that a volume could be a junction point... so if newname is q:\SomeJunctionDirectory\hello.txt and the old name is c:\TargetOfJunctionPoint\hello.txt... the files are the same but the names aren't. – Adrian Hum Oct 14 '16 at 01:26

20 Answers20

1196

Take a look at System.IO.File.Move, "move" the file to a new name.

System.IO.File.Move("oldfilename", "newfilename");
Chris Taylor
  • 52,623
  • 10
  • 78
  • 89
  • 23
    This solution does not work when file names differ only in letter case. For example file.txt and File.txt – SepehrM Jul 06 '14 at 20:31
  • 3
    @SepehrM, I just double checked and it works fine on my Windows 8.1 machine. – Chris Taylor Jul 07 '14 at 01:57
  • I'm not sure why this happens but take a look at these posts: http://stackoverflow.com/questions/8152731/file-or-folder-rename-to-lower-case-in-c-sharp-using-directoryinfo-fileinfo-move and http://www.codeproject.com/Tips/365773/Rename-a-directory-or-file-name-to-lower-case-with – SepehrM Jul 07 '14 at 06:43
  • 1
    @SepehrM, I did not test it, but the samples you point to use FileInfo.Move and not File.Move so maybe that has something to do with it? – Chris Taylor Jul 07 '14 at 12:31
  • Thanks for getting back. Unfortunately I tested with `File.Move` and still have the same issue! – SepehrM Jul 07 '14 at 13:48
  • What OS are you testing on? – Chris Taylor Jul 07 '14 at 17:49
  • Windows 8.1 Enterprise. We first encountered this error on one of our test machines whose OS is the same. This issue does NOT always occur. Sometimes we see a different behavior and I have no idea as to what causes this issue. – SepehrM Jul 07 '14 at 19:47
  • It is curious that you say it does not always happen, so sometimes the filename does change case. Just to ask the obvious, have you checked that the operation is not possibly failing? Maybe you have a try/catch which is catching an exception and now showing it? Just some guesses, so I don't know if they will help. – Chris Taylor Jul 07 '14 at 19:56
  • Yes, all exceptions are logged automatically. For now I'm basically renaming the file to a random name and then renaming it back to the desired one. I'll get back to you if I ever find the cause of this problem. – SepehrM Jul 07 '14 at 20:13
  • I also found this to work with a little extra code after uploading to IIS. No delete required. System.IO.File.Move(Path.Combine(HttpContext.Server.MapPath("~/FileUploads/Photography/"), item.Filename), Path.Combine(HttpContext.Server.MapPath("~/FileUploads/Photography/"), "test.nef")); – JQII Sep 25 '14 at 14:00
  • I wish MS provided a better method. One has to deal with file extensions too – DeathRs Apr 13 '16 at 08:36
  • 3
    @SepehrM Windows file system names are case insensitive. File.txt and file.txt are treated as the same file name. So it's not clear to me when you say the solution doesn't work. What are you doing exactly that isn't working? – Michael Oct 17 '16 at 17:35
  • 6
    @Michael, the file system is case insensitive, but it does store the filename in the original case as entered by the user. In SepehrM's case, he was trying to change the case of a file, which for some reason was not working. The case insensitive matching was working. HTH – Chris Taylor Oct 18 '16 at 00:08
  • Here, we should take into account that both `oldfilename` and `newfilename` are referring to the full path of the file (example: "D:\\MyProjects\\XProj\\myFile.txt"). And second when renaming we should exclude file name and extension from full path, i.e. `$"{Path.GetDirectoryName(fullPath)}\\NewFileName{extension}")` – Arsen Khachaturyan Mar 22 '20 at 16:37
  • @ArsenKhachaturyan, you only need the full path if the file is not in the current working directory. If the file to be renamed is in the current working directory you only need to specify the filename. – Chris Taylor Mar 23 '20 at 15:30
  • @ChrisTaylor agree with you, it's kind of thing to remember to do. So generally good practice could be to use the full path, to not encounter bad surprises. – Arsen Khachaturyan Mar 23 '20 at 16:20
  • 3
    Just FYI for everyone, you will only have problems with case sensitive files not changing if they fall into the old 8.3 limit. – PRMan Aug 25 '20 at 23:00
  • To workaround the case insensitive filename, one could rename to a random filename using `Path.GetRandomFileName()` and then rename back to the different cased filename. If you are not comfortable doing this for everything, you could do a case-insensitive check for both names, and apply this trick only when they match. – Emrah 'hesido' Baskaya Jun 01 '21 at 06:44
152
System.IO.File.Move(oldNameFullPath, newNameFullPath);
Filip Ekberg
  • 36,033
  • 20
  • 126
  • 183
Aleksandar Vucetic
  • 14,715
  • 9
  • 53
  • 56
58

In the File.Move method, this won't overwrite the file if it is already exists. And it will throw an exception.

So we need to check whether the file exists or not.

/* Delete the file if exists, else no exception thrown. */

File.Delete(newFileName); // Delete the existing file if exists
File.Move(oldFileName,newFileName); // Rename the oldFileName into newFileName

Or surround it with a try catch to avoid an exception.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mohamed Alikhan
  • 1,315
  • 11
  • 14
  • 29
    be really careful with this approach... if your destination directory and your source directory are the same, and the "newname" actually a case-sensitive version of "oldFileName", you will delete before you get a chance to move your file. – Adrian Hum Oct 14 '16 at 01:16
  • 2
    You also cannot just check the strings for equality as there are several ways of representing a single file path. – Drew Noakes Dec 13 '17 at 22:03
  • 3
    File.Move has an overload method now that allows you to overwrite the file - File.Move(oldPath, newPath, true) – Ella Apr 05 '20 at 22:15
  • @Ella I don't see that third parameter in File.Move. – RobertSF Oct 04 '20 at 19:02
  • 1
    @RobertSF It's in .Net core 3.0 and later - https://learn.microsoft.com/en-us/dotnet/api/system.io.file.move?view=netcore-3.1#System_IO_File_Move_System_String_System_String_System_Boolean_ – Ella Oct 14 '20 at 19:07
  • 1
    @Ella Indeed. It's still not in .Net Framework 4.6.1, unfort. – RobertSF Oct 19 '20 at 00:00
49

Just add:

namespace System.IO
{
    public static class ExtendedMethod
    {
        public static void Rename(this FileInfo fileInfo, string newName)
        {
            fileInfo.MoveTo(fileInfo.Directory.FullName + "\\" + newName);
        }
    }
}

And then...

FileInfo file = new FileInfo("c:\test.txt");
file.Rename("test2.txt");
davidsbro
  • 2,761
  • 4
  • 23
  • 33
Nogro
  • 564
  • 4
  • 6
39

You can use File.Move to do it.

Franci Penov
  • 74,861
  • 18
  • 132
  • 169
23
  1. First solution

    Avoid System.IO.File.Move solutions posted here (marked answer included). It fails over networks. However, copy/delete pattern works locally and over networks. Follow one of the move solutions, but replace it with Copy instead. Then use File.Delete to delete the original file.

    You can create a Rename method to simplify it.

  2. Ease of use

    Use the VB assembly in C#. Add reference to Microsoft.VisualBasic

    Then to rename the file:

    Microsoft.VisualBasic.FileIO.FileSystem.RenameFile(myfile, newName);

    Both are strings. Note that myfile has the full path. newName does not. For example:

    a = "C:\whatever\a.txt";
    b = "b.txt";
    Microsoft.VisualBasic.FileIO.FileSystem.RenameFile(a, b);
    

    The C:\whatever\ folder will now contain b.txt.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ray
  • 243
  • 2
  • 4
  • 12
    just so you know, Microsoft.VisualBasic.FileIO.FileSystem.RenameFile calls File.Move. Other thank normalizing the original file and doing some additional error checks on the arguments ie. file exists, file name not null etc. it then calls File.Move. – Chris Taylor Jul 07 '14 at 02:07
  • Unless Copy() copies all file streams, which I assume it doesn't, I would stay away from using delete/copy. I assume Move(), at least when staying on the same file system, is simply a rename and thus all file streams will be maintained. –  Dec 01 '16 at 00:54
  • "it fails over the network" then you're going to copy & delete which is actually download & upload, just for code-time convenience... What kind of network? Windows shared folder (`smb`), `ftp` , `ssh` or whatever all have commands/primitives for file moving/renaming unless not permitted (e.g. read-only). – Meow Cat 2012 Aug 27 '19 at 03:18
17

You can copy it as a new file and then delete the old one using the System.IO.File class:

if (File.Exists(oldName))
{
    File.Copy(oldName, newName, true);
    File.Delete(oldName);
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Zaki Choudhury
  • 1,497
  • 15
  • 6
  • 5
    Note to anyone reading this: This is an anti-pattern, the file might be deleted or renamed by another process or the OS between the check for if it exists and your call to Copy. You need to instead use a try catch. – user9993 Apr 20 '16 at 15:31
  • If the volume is the same, this is also a huge waste of I/O since a move would actually do a rename at directory information level. – Adrian Hum Oct 14 '16 at 01:20
  • I am processing thousands of files and got the impression Copy/Delete is faster than Move. – Santos Aug 03 '19 at 22:52
  • How would anyone come up with such an idea. Faster or not at least you're murdering the disk. By saying "rename" in the question it should means rename locally which of course involves no cross-partition moving. – Meow Cat 2012 Aug 27 '19 at 03:14
  • with File.Move I ran into UnauthorizedAccessException, but this sequence of Copy and Delete worked. Thanks! – Oliver Konig Sep 06 '19 at 14:16
12
public void RenameFile(string filePath, string newName)
{
    FileInfo fileInfo = new FileInfo(filePath);
    fileInfo.MoveTo(fileInfo.Directory.FullName + "\\" + newName);
}
Majedur
  • 3,074
  • 1
  • 30
  • 43
8

NOTE: In this example code we open a directory and search for PDF files with open and closed parenthesis in the name of the file. You can check and replace any character in the name you like or just specify a whole new name using replace functions.

There are other ways to work from this code to do more elaborate renames but my main intention was to show how to use File.Move to do a batch rename. This worked against 335 PDF files in 180 directories when I ran it on my laptop. This is spur of the moment code and there are more elaborate ways to do it.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BatchRenamer
{
    class Program
    {
        static void Main(string[] args)
        {
            var dirnames = Directory.GetDirectories(@"C:\the full directory path of files to rename goes here");

            int i = 0;

            try
            {
                foreach (var dir in dirnames)
                {
                    var fnames = Directory.GetFiles(dir, "*.pdf").Select(Path.GetFileName);

                    DirectoryInfo d = new DirectoryInfo(dir);
                    FileInfo[] finfo = d.GetFiles("*.pdf");

                    foreach (var f in fnames)
                    {
                        i++;
                        Console.WriteLine("The number of the file being renamed is: {0}", i);

                        if (!File.Exists(Path.Combine(dir, f.ToString().Replace("(", "").Replace(")", ""))))
                        {
                            File.Move(Path.Combine(dir, f), Path.Combine(dir, f.ToString().Replace("(", "").Replace(")", "")));
                        }
                        else
                        {
                            Console.WriteLine("The file you are attempting to rename already exists! The file path is {0}.", dir);
                            foreach (FileInfo fi in finfo)
                            {
                                Console.WriteLine("The file modify date is: {0} ", File.GetLastWriteTime(dir));
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            Console.Read();
        }
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
MicRoc
  • 117
  • 1
  • 5
  • 3
    That's... completely beside the point, on a question answered exactly to the point 3 years ago. – Nyerguds Nov 19 '13 at 11:33
  • 3
    It's a valid example. Overkill maybe but not beside the point. +1 – Adam Nov 27 '13 at 09:11
  • 1
    @Adam: it's a very specific implementation of exactly the answer that was already given three years before, on a question that wasn't about any specific implementation in the first place. Don't see how that's in any way constructive. – Nyerguds Dec 05 '13 at 10:52
  • @Nyerguds then we have different definitions of 'beside the point', which is not surprising since it's a subjective term. – Adam Dec 06 '13 at 11:20
  • @Nyerguds if it's irrelevant for you then that is fine. Some people like verbosity because it helps them to find "real world" implementations of "sample/example" code. It renames file(s). How it is beside the point is pretty much as Adam said, it's subjective. For some reason you feel it to be absolutely objective. Oh well, to each his own. Thanks for the input, either way. – MicRoc Feb 12 '14 at 05:27
7

None of the answers mention writing a unit testable solution. You could use System.IO.Abstractions as it provides a testable wrapper around FileSystem operations, using which you can create a mocked file system objects and write unit tests.

using System.IO.Abstractions;

IFileInfo fileInfo = _fileSystem.FileInfo.FromFileName("filePathAndName");
fileInfo.MoveTo(Path.Combine(fileInfo.DirectoryName, newName));

It was tested, and it is working code to rename a file.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Adil H. Raza
  • 1,649
  • 20
  • 25
6

Use:

using System.IO;

string oldFilePath = @"C:\OldFile.txt"; // Full path of old file
string newFilePath = @"C:\NewFile.txt"; // Full path of new file

if (File.Exists(newFilePath))
{
    File.Delete(newFilePath);
}
File.Move(oldFilePath, newFilePath);
zwcloud
  • 4,546
  • 3
  • 40
  • 69
Avinash Singh
  • 2,697
  • 11
  • 44
  • 72
  • 8
    If you're going to do this, I'd suggest checking that the 'oldFilePath' exists before doing anything... or else you'll delete the 'newFilePath' for no reason. – John Kroetch Jul 09 '14 at 19:18
6

Use:

public static class FileInfoExtensions
{
    /// <summary>
    /// Behavior when a new filename exists.
    /// </summary>
    public enum FileExistBehavior
    {
        /// <summary>
        /// None: throw IOException "The destination file already exists."
        /// </summary>
        None = 0,
        /// <summary>
        /// Replace: replace the file in the destination.
        /// </summary>
        Replace = 1,
        /// <summary>
        /// Skip: skip this file.
        /// </summary>
        Skip = 2,
        /// <summary>
        /// Rename: rename the file (like a window behavior)
        /// </summary>
        Rename = 3
    }


    /// <summary>
    /// Rename the file.
    /// </summary>
    /// <param name="fileInfo">the target file.</param>
    /// <param name="newFileName">new filename with extension.</param>
    /// <param name="fileExistBehavior">behavior when new filename is exist.</param>
    public static void Rename(this System.IO.FileInfo fileInfo, string newFileName, FileExistBehavior fileExistBehavior = FileExistBehavior.None)
    {
        string newFileNameWithoutExtension = System.IO.Path.GetFileNameWithoutExtension(newFileName);
        string newFileNameExtension = System.IO.Path.GetExtension(newFileName);
        string newFilePath = System.IO.Path.Combine(fileInfo.Directory.FullName, newFileName);

        if (System.IO.File.Exists(newFilePath))
        {
            switch (fileExistBehavior)
            {
                case FileExistBehavior.None:
                    throw new System.IO.IOException("The destination file already exists.");

                case FileExistBehavior.Replace:
                    System.IO.File.Delete(newFilePath);
                    break;

                case FileExistBehavior.Rename:
                    int dupplicate_count = 0;
                    string newFileNameWithDupplicateIndex;
                    string newFilePathWithDupplicateIndex;
                    do
                    {
                        dupplicate_count++;
                        newFileNameWithDupplicateIndex = newFileNameWithoutExtension + " (" + dupplicate_count + ")" + newFileNameExtension;
                        newFilePathWithDupplicateIndex = System.IO.Path.Combine(fileInfo.Directory.FullName, newFileNameWithDupplicateIndex);
                    }
                    while (System.IO.File.Exists(newFilePathWithDupplicateIndex));

                    newFilePath = newFilePathWithDupplicateIndex;
                    break;

                case FileExistBehavior.Skip:
                    return;
            }
        }
        System.IO.File.Move(fileInfo.FullName, newFilePath);
    }
}

How to use this code

class Program
{
    static void Main(string[] args)
    {
        string targetFile = System.IO.Path.Combine(@"D://test", "New Text Document.txt");
        string newFileName = "Foo.txt";

        // Full pattern
        System.IO.FileInfo fileInfo = new System.IO.FileInfo(targetFile);
        fileInfo.Rename(newFileName);

        // Or short form
        new System.IO.FileInfo(targetFile).Rename(newFileName);
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
6

I couldn't find an approach which suits me, so I propose my version. Of course, it needs input and error handling.

public void Rename(string filePath, string newFileName)
{
    var newFilePath = Path.Combine(Path.GetDirectoryName(filePath), newFileName + Path.GetExtension(filePath));
    System.IO.File.Move(filePath, newFilePath);
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
valentasm
  • 2,137
  • 23
  • 24
3

In my case, I want the name of the renamed file to be unique, so I add a date-time stamp to the name. This way, the filename of the 'old' log is always unique:

if (File.Exists(clogfile))
{
    Int64 fileSizeInBytes = new FileInfo(clogfile).Length;
    if (fileSizeInBytes > 5000000)
    {
        string path = Path.GetFullPath(clogfile);
        string filename = Path.GetFileNameWithoutExtension(clogfile);
        System.IO.File.Move(clogfile, Path.Combine(path, string.Format("{0}{1}.log", filename, DateTime.Now.ToString("yyyyMMdd_HHmmss"))));
    }
}
Wang Liang
  • 4,244
  • 6
  • 22
  • 45
real_yggdrasil
  • 1,213
  • 4
  • 14
  • 27
2

Move is doing the same = copy and delete old one.

File.Move(@"C:\ScanPDF\Test.pdf", @"C:\BackupPDF\" + string.Format("backup-{0:yyyy-MM-dd_HH:mm:ss}.pdf", DateTime.Now));
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Nalan Madheswaran
  • 10,136
  • 1
  • 57
  • 42
1
// Source file to be renamed  
string sourceFile = @"C:\Temp\MaheshChand.jpg";  
// Create a FileInfo  
System.IO.FileInfo fi = new System.IO.FileInfo(sourceFile);  
// Check if file is there  
if (fi.Exists)  
{  
// Move file with a new name. Hence renamed.  
fi.MoveTo(@"C:\Temp\Mahesh.jpg");  
Console.WriteLine("File Renamed.");  
}  
0
public static class ImageRename
{
    public static void ApplyChanges(string fileUrl,
                                    string temporaryImageName,
                                    string permanentImageName)
    {
        var currentFileName = Path.Combine(fileUrl,
                                           temporaryImageName);

        if (!File.Exists(currentFileName))
            throw new FileNotFoundException();

        var extention = Path.GetExtension(temporaryImageName);
        var newFileName = Path.Combine(fileUrl,
                                       $"{permanentImageName}
                                         {extention}");

        if (File.Exists(newFileName))
            File.Delete(newFileName);

        File.Move(currentFileName, newFileName);
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Amin Golmahalleh
  • 3,585
  • 2
  • 23
  • 36
0

I've encountered a case when I had to rename the file inside the event handler, which was triggering for any file change, including rename, and to skip forever renaming of the file I had to rename it, with:

  1. Making its copy
  2. Removing the original
File.Copy(fileFullPath, destFileName); // Both have the format of "D:\..\..\myFile.ext"
Thread.Sleep(100); // Wait for the OS to unfocus the file
File.Delete(fileFullPath);
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Arsen Khachaturyan
  • 7,904
  • 4
  • 42
  • 42
  • if you used an using block you could remove thread.sleep and let the program unfocus it automatically, right? – Uke Aug 04 '20 at 12:24
  • 1
    @Zoba, if you meant applying `using` block over `File.Copy` or `File.Delete` static methods, then you should know that's not possible because both of them return `void`. To use `using` statement, the return type of the method (including constructor) should be the object which type implements the `IDisposable` interface. – Arsen Khachaturyan Aug 04 '20 at 17:45
0
private static void Rename_File(string FileFullPath, string NewName) // nes name without directory actualy you can simply rename with fileinfo.MoveTo(Fullpathwithnameandextension);
        {
            FileInfo fileInfo = new FileInfo(FileFullPath);
            string DirectoryRoot = Directory.GetParent(FileFullPath).FullName;

            string filecreator = FileFullPath.Substring(DirectoryRoot.Length,FileFullPath.Length-DirectoryRoot.Length);
             
            filecreator = DirectoryRoot + NewName;
            try
            {
                fileInfo.MoveTo(filecreator);
            }
            catch(Exception ex)
            {
                Console.WriteLine(filecreator);
                Console.WriteLine(ex.Message);
                Console.ReadKey();
            }

    enter code here
            // string FileDirectory = Directory.GetDirectoryRoot()

        }
Igor
  • 55
  • 1
  • 3
-11

When C# doesn't have some feature, I use C++ or C:

public partial class Program
{
    [DllImport("msvcrt", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
    public static extern int rename(
            [MarshalAs(UnmanagedType.LPStr)]
            string oldpath,
            [MarshalAs(UnmanagedType.LPStr)]
            string newpath);

    static void FileRename()
    {
        while (true)
        {
            Console.Clear();
            Console.Write("Enter a folder name: ");
            string dir = Console.ReadLine().Trim('\\') + "\\";
            if (string.IsNullOrWhiteSpace(dir))
                break;
            if (!Directory.Exists(dir))
            {
                Console.WriteLine("{0} does not exist", dir);
                continue;
            }
            string[] files = Directory.GetFiles(dir, "*.mp3");

            for (int i = 0; i < files.Length; i++)
            {
                string oldName = Path.GetFileName(files[i]);
                int pos = oldName.IndexOfAny(new char[] { '0', '1', '2' });
                if (pos == 0)
                    continue;

                string newName = oldName.Substring(pos);
                int res = rename(files[i], dir + newName);
            }
        }
        Console.WriteLine("\n\t\tPress any key to go to main menu\n");
        Console.ReadKey(true);
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131