Search code examples
c#fileinfo

How to Refresh FileInfo if someone concurrently updates the capitalization of the file name


Initially, my file is named "my file.txt"

var file = new FileInfo("C:\my file.txt");

The file is renamed to "My File.txt" while my code is running. How can my code refresh the file name?

file.Refresh();

does not update the spelling in Name property.

-- Edit --

Ok, I'll do this then

 file = file.Directory.GetFiles(file.Name).First();

Case matters when an application lists the files as content to be inserted into a document and the customer asks for a certain case to be displayed.


Solution

  • The Refresh method only refreshes these attributes of the FileInfo instance. As you can see the filename isn't part of that.

    // Copy the information to data
    fileAttributes = findData.dwFileAttributes;
    ftCreationTime = findData.ftCreationTime;
    ftLastAccessTime = findData.ftLastAccessTime;
    ftLastWriteTime = findData.ftLastWriteTime;
    fileSizeHigh = findData.nFileSizeHigh;
    fileSizeLow = findData.nFileSizeLow;
    

    What you can do is having a new implementation of a FileSystemInfo class that leverages a FileSystemWatcher to track renames of a file that is given to a FileInfo instance.

    This is what the proof-of-concept looks like. In the constructor we also setup FileSystemWatcher for the directory the file is in. We filter for name changes and wireup the Renamed event of the FileSystemWatcher. If the name change is indeed for the file we track (done by doing an ignore case comparison of the filenames) we replace the current FileInfo instance with a new one.

    public class LiveFileInfo:FileSystemInfo
    {
       FileInfo fi;
       FileSystemWatcher watcher;
       public LiveFileInfo(string filename ):base()
       {
            fi = new FileInfo(filename);
            watcher = new FileSystemWatcher(fi.DirectoryName);
    
            watcher.NotifyFilter = NotifyFilters.DirectoryName | NotifyFilters.FileName;
       
            watcher.Renamed += (sender, args) => {
                 if (args.OldFullPath.Equals(fi.FullName, StringComparison.InvariantCultureIgnoreCase)) {
                   fi = new FileInfo(args.FullPath);            
                 }
            };
            watcher.EnableRaisingEvents = true;
       }
       
       public  override string Name {
          get {
             return fi.Name;
          }
       }
       
       public override bool Exists {
         get {
          return fi.Exists;
          }
       }
       
       public override void Delete() {
       }
    }
    

    This is how you would use it:

       var lfi = new LiveFileInfo(@"c:\tmp\test.txt");
       
       lfi.Name.Dump("before name");
       
       Console.ReadLine();
    
       lfi.Name.Dump("name");
    

    With this as result:

    enter image description here

    Ideally you would Dispose the FileSystemWatcher. I leave that as an exercise for the reader as that needs a Dispose implementation on the LiveFileInfo class.