5

In C#, I open a file with FileShare.Delete. This allows me to open the file without restricting other processes from deleting it. For example:

using (FileStream fs = new FileStream(@"C:\temp\1.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete))
{
    int len = (int)fs.Length;
    byte[] array = new byte[len];
    int bytesRead = fs.Read(array, 0, len);
}

My questions are:

  1. What happens if the file is deleted by a different process after we created the stream, but before we read it? Does the operating system keep a copy of the file until the stream\handle is closed?
  2. Can I rely on reading the deleted file without getting any errors, or the wrong content?
MoonRabbit
  • 89
  • 6
  • 1
    File can't be deleted if it is opened by your process – Pikoh Oct 10 '16 at 08:41
  • 1
    They can be deleted if you open them with FileShare.Delete – MoonRabbit Oct 10 '16 at 08:45
  • You are right @MoonRobbit, didn't notice that – Pikoh Oct 10 '16 at 08:48
  • 1
    You are right about FileShare.Delete. Check this question, Possible duplicate of [Can using FileShare.Delete cause a UnauthorizedAccessException?](http://stackoverflow.com/questions/19875329/can-using-fileshare-delete-cause-a-unauthorizedaccessexception) – mybirthname Oct 10 '16 at 08:54

2 Answers2

6

The file is marked for deletion, but is not actually deleted until the last open handle to it is closed, as described in the documentation for DeleteFile.

Note that you cannot open a new handle to a file that is marked for deletion, but the file will still appear in directory listings and cannot be replaced by a file of the same name until it has actually been deleted. This is unlike Unix systems in which the file disappears from the directory (is "unlinked") immediately. As Ben suggests in the comments, you can work around this by renaming and/or moving the file before deleting it.

Also, as MoonRabbit pointed out, you can "delete" an open file using Explorer, but that is because that only moves the file to the recycle bin. The Shift+Delete option to delete a file immediately won't work.

Harry Johnston
  • 35,639
  • 6
  • 68
  • 158
  • 2
    Subtle difference between Unix and Windows semantics -- on both, the file is not deleted so long as any handle is open, but on Unix systems, it is unlinked from the directory immediately and then deleted when the last handle is closed, while on Windows unlinking is delayed like deletion. Very important difference if you plan to use the same name to create a new file. A good approach on Windows is to rename the file before deleting, that way if unlinking is delayed it doesn't continue occupying the name. – Ben Voigt Oct 11 '16 at 00:18
  • I tried to run my test program, and while the stream is open, I deleted the file, and then replaced it with a new one of the same name. According to you this shouldn't work, but it did. How come? – MoonRabbit Oct 13 '16 at 07:07
  • Okay, apparently using DeleteFile (or File.Delete in C#) does what you explained, but removing a file with explorer.exe (right click->delete) somehow manage to make the file dissappear. – MoonRabbit Oct 13 '16 at 07:24
  • 1
    I'll answer myself: it worked because removing the file moves it to the recycle bin. If I use shift+delete, I'm really unable to make a file with this name until the handle is closed. – MoonRabbit Oct 13 '16 at 07:48
0

Yes another process can delete the file but you will not get any exception as the pointer to the file on the disk was created so your process will continue reading, but when you retry to open the stream you will get an exception as the entry in the file system does not exist

here a full example to reproduce your case

try to execute this and go to explorer and delete your file

 class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 10000; i++)
            {
                File.AppendAllText(@"c:\temp\1.txt", Guid.NewGuid().ToString());  
            }
            //read the file 
            using (FileStream fs = new FileStream(@"C:\temp\1.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete))
            {
                while (fs.CanRead)
                {
                    //here I read a chunk of 1000 bytes to let stream open 
                    int len = 1000;
                    Thread.Sleep(1000);
                    byte[] array = new byte[len];
                    int bytesRead = fs.Read(array, 0, len);
                }
            }

        }
    }
BRAHIM Kamel
  • 13,492
  • 1
  • 36
  • 47