0

I'm using a filestream to access a file (making an md5 ComputeHash). If I attempt to rename the file during this time (which fails as the file is being accessed). So far so good, but when I then try to open the file anew after the original filestream is closed I get the info that the file is open in another process.

Code:

using (Stream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
    MD5 md5 = MD5.Create();
    byte[] mymd5computed = md5.ComputeHash(fileStream);
    ......
}
Thread.Sleep(50);

Thread a = new Thread (()=>{(FileStream sourceStream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){....} });

Like I said if while during the computation of the MD5 I try to rename the file I get the info that the file is still locked.

Thomas
  • 2,886
  • 3
  • 34
  • 78

1 Answers1

0

The lock on a file sometimes isn't released right away when you close your stream, so there are some other solutions you can use to wait until you can access the file again. One of them is explained here: http://www.codeproject.com/Tips/164428/C-FileStream-Lock-How-to-wait-for-a-file-to-get-re.

Recap:

public static void Lock(string path, Action<FileStream> action) {
    var autoResetEvent = new AutoResetEvent(false);

    while(true)
    {
        try
        {
            using (var file = File.Open(path,
                                        FileMode.OpenOrCreate,
                                        FileAccess.ReadWrite,
                                        FileShare.Write))
            {
                action(file);
                break;
            }
        }
        catch (IOException)
        {
            var fileSystemWatcher =
                new FileSystemWatcher(Path.GetDirectoryName(path))
                        {
                            EnableRaisingEvents = true
                        };

            fileSystemWatcher.Changed +=
                (o, e) =>
                    {
                        if(Path.GetFullPath(e.FullPath) == Path.GetFullPath(path))
                        {
                            autoResetEvent.Set();
                        }
                    };

            autoResetEvent.WaitOne();
        }
    } 
}

Sample use:

Lock(@"c:\file",
        (f) =>
            {
                try
                {
                    f.Write(buf, 0, buf.Length);
                }
                catch(IOException ioe)
                {
// handle IOException
                }
            });

Hope it helps! :)

Andrej Kikelj
  • 800
  • 7
  • 11
  • Ouch that is the worst case I had feared. is there any other possibility than to put a wrapper around the file operations? (would need to rewrite almost 1k lines of code there). – Thomas Aug 13 '14 at 12:30
  • It's not an ideal situation, but from my previous experience, sometimes that's all you can do. It's not only your app that could lock the file, it could also be locked by an AV between your calls, though highly unlikely. Some try to cure the lock problem by using Thread.Sleep() like you did, but I find this to be a bit too "unexpected", since it could take a few ms longer to be released, or it could be locked again in the meantime. If you can live with a longer Thread.Sleep, that should be OK, but won't be 100%. FileSystem can keep it locked even when you dispose and close the stream. – Andrej Kikelj Aug 13 '14 at 12:42
  • I'm currently trying to see a way to be able to differentate programwise between "file is only open a few ms as closing still takes time" and "another application has it open" (example someone has the file open in word). is there any way where I can tell if its my application that is doing the lock? (else I will have to add sort of a timeout there for the waiting as when another application has the file opened the user needs to know it via exception and messagebox to be able to act accordingly). As example: A maximum waiting time of 1 second as timeout. – Thomas Aug 13 '14 at 12:50
  • http://stackoverflow.com/a/1121236/1361993 this answer should help you find the locking process using handle.exe, if that's exceptable for you - I guess if you parse the processes locking the file and see that your app is not the one locking it, you can warn the user what process to kill in order to proceed. – Andrej Kikelj Aug 13 '14 at 12:55
  • Tnx. So in total 2 possibilities: a.) Using your lock variant with/without checking processes to be able to inform the user that one of his applications has the file open b.) using only 1 filehandle throughout all operations and don't close it (in this case if it is open already that open must have come from a different application). – Thomas Aug 13 '14 at 12:58
  • Can't take the credit for the Lock function, it was written by the original poster in the linked post, but yeah I think that your method should work. It would probably also be more efficient if you only use one handle throughout the lifespan of the file in your app, instead of reopening it, if you are doing this at scale and sequential. – Andrej Kikelj Aug 13 '14 at 13:01
  • Yepp will have to see there if 1 handle is possible with the current architecture else will use your method there. Tnx alot there. The file not immediately closing when you close the handle is probably the reason for QUITE a lot of strange phenomenons I have encountered in the last 2 weeks with my program. tnx alot there! – Thomas Aug 13 '14 at 13:03
  • No problem, that's how it is with FileSystem, I tend to over-protect anything I'm doing around FS because of this, of course depending on the level of reliability I want to be at. Glad I could have helped! – Andrej Kikelj Aug 13 '14 at 13:14
  • Tbh I NEVER ran into this problem before (neither during my 10 years as a web programmer nor during the now 4 months of C# programmer, only now). Until now I have trusted the FS but tnx to this I'll be quite cautious now in regards to FS operations. tnx again – Thomas Aug 13 '14 at 13:23
  • One thing I just remembered. Did you ever see the problem also happening if you use FileInfo (to get the name and the size of the file) or is that one "save" to use in these regards? – Thomas Aug 13 '14 at 13:30
  • [This answer](http://stackoverflow.com/a/14182539/1361993) explains it pretty much in depth: FileInfo exclusively gives you the metadata for a file. The file data is much more sensitive, highly subject to change as a process writes to the file. Notable is that you can lock access to the file data with the FileShare options. But there's no way to lock the metadata. Accordingly you can always get the FileInfo for a file, assuming security doesn't lock you out and the file still exists, regardless what another process is doing with the file. Never used FileInfo in such scenario myself though. – Andrej Kikelj Aug 13 '14 at 18:21