I'm working with MIP SDK 1.12 and 1.11 on Windows, and noticed that if I use a IFileHandler for a file of type .msg, the file remains locked after use, and this can cause IOErrors later on in the application if the file gets accessed.
This only happens for .msg files and not for any other file type, and happens also with read-only actions for example getting the file label or checking if the file is protected.
Even when the variable for IFileHandler gets out of scope, the file remains locked, so I tested by explicitly calling Dispose() on IFileHandler, and this seems to solve the issue.
Is this a bug and will be fixed in the next release?
Do you see any potential issue for explicit call on Dispose() for the other file types?
Related
I'm using a FileSystemWatcher to watch a directory. I created a _Created() event handler to fire when a file is moved to this folder. My problem is the following:
The files in this directory get created when the user hits a "real life button" (a button in our stock, not in the application). The FileSystemWatcher take this file, do some stuff in the system and then delete it. That wouldn't be a problem when the application runs only once. But it is used by 6 clients. So every application on every client is trying to delete it. If one client is too slow, it will throw an exception because the file is already deleted.
What I'm asking for is: Is there a way to avoid this?
I tried using loops and check if the file still exists, but without any success.
while (File.Exists(file))
{
File.Delete(file);
Thread.Sleep(100);
}
Can someone give me a hint how it could probably work?
Design
If you want a file to be processed by a single instance only (for example, the first instance that reacts gets the job), then you should implement a locking mechanism. Only the instance that is able to obtain a lock on the file is allowed to process and remove it, all other instances should skip the file.
If you're fine with all instances processing the file, and only care that at least one of them succeeds, then you need to figure out which exceptions indicate a genuine failure and which ones indicate a failure caused by the actions of another instance.
Locking
To 'lock' a file, you can open it with share-mode FileShare.None. This prevents other processes from opening it until you close the file. However, you'll then need to close the file before you can delete it, which leaves a small gap during which another instance could open the file.
A better solution is to create a separate lock file for that purpose. Create it with file-mode FileMode.Create and share-mode FileShare.None and keep it open until the whole process is finished, including the removal of the processed file. Then the lock file can be closed and optionally removed.
Exception
As for the UnauthorizedAccessException you got, according to the documentation, that means one of 4 things:
You don't have the required permission
The file is an executable file that is in use
The path is a directory
The file is read-only
1 and 4 seem most likely in this case (if the file was open in another process you'd get an IOException).
If you want to synchronize access between multiple clients on the same computer you should use a Named Mutex.
This question already has answers here:
File.Move Does Not Work - File Already Exists
(9 answers)
Closed 2 years ago.
I'm developing a multi threaded application. I have somewhere in my code :
File.Delete(sidetapedata);
File.Move(sidetapedata2, sidetapedata); //sidetapedata and sidetapedata2 are two file paths that correspond to sidetapedata.txt and sidetaptdata2.txt in some directory.
The second line sometimes runs fine and other times, it throws an IOException :
Cannot create a file when that file already exists.
There is one more thread that is accessing the sidetapedata file but that one is only reading this file, no write operations. I am using locks to protect race conditions. Don't know why this is happening.
UPDATE : even when visual c# debugger shows me this exception, looking into the directory that contains these files, I see there is no sidetapedata.txt file but there is a sidetapedata2.txt file!
UPDATE2 : Also, this behavior only happens when sidetapedata.txt and sidetapedata2.txt are both blank
Not sure why this would happen unless there's some event triggered in the file system by the Delete call which means it's not actually deleted until slightly after the call returns. A few options:
You could loop (with some sort of maximum number of loops before erroring) where you check for the file's existence before trying the move, and sleep briefly if it still exists after deletion
You could use File.Copy(sidetapedata, sidetapedata2, true) to copy instead of moving, and then delete the source file. This will be less efficient though, assuming the move would be handled by a simple file system directory entry change (rather than really copying the data)
You could use File.Move on the target file instead of File.Delete to move it to some harmless other filename, then delete that afterwards, hoping that the Move is more atomic than the Delete.
I suspect the threading is irrelevant here - I suggest you write a short but complete program to validate that, so you can rule it out (and easily test the workarounds).
I am unsure if this is the same for .NET, but according to the win32 DeleteFile api reference:
The DeleteFile function marks a file for deletion on close. Therefore, the file deletion does not occur until the last handle to the file is closed.
So there is probably a window of time between the call to Delete returning and Windows closing the last handle to the file. It looks like you are calling Move during this period of time.
In .NET Core 3.0 and later versions, you can call Move(String, String, Boolean) setting the parameter overwrite to true, which will replace the file if it exists.
see https://learn.microsoft.com/en-us/dotnet/api/system.io.file.move?view=netcore-3.0
As per this answer : use FileStream with FileShare
FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
The following throws an exception "The process cannot access the file 'D:\MyDir\First.txt' because it is being used by another process."
static void Main(string[] args)
{
Directory.CreateDirectory(#"D:\MyDir");
File.Create(#"D:\MyDir\First.txt");
File.WriteAllText(#"D:\MyDir\First.txt", "StackOverflow.com");
}
However following works:
using (File.Create(#"D:\MyDir\First.txt"))
{
}
or
File.Create(#"D:\MyDir\First.txt").Close();
Why? What in File.Create needs to be closed?
File.Create is doing more than you think here. It's not just creating the file, it's also returning an active stream to the file. However, you're not doing anything with that stream. The using block in your latter example closes that stream by disposing it.
Note also that this is a significant clue about the return value:
File.Create(#"D:\MyDir\First.txt").Close();
(It actually wasn't intuitive to me when I first read your question, but looking back at it this line of code actually says it all.)
Your next step, calling File.WriteAllText also does more than you think. According to the documentation, it:
Creates a new file, writes the specified string to the file, and then closes the file.
So it would seem that your File.Create call isn't really needed here anyway.
Because it opens a file stream, which is a class managing some operating system low-level resources and those must be released in order to let other operations in other threads, and even in other applications, access to the file.
You don't actually need to call File.Create() to then be able to call File.WriteAllText().
File.WriteAllText() will create a new file and write to it then close the file all in one handy method.
If the file already exists it'll be overwritten.
The MSDN docs for File.Create() explain this:
The FileStream object created by this
method has a default FileShare value
of None; no other process or code can
access the created file until the
original file handle is closed.
Basically until the file create is closed the file cannot be access by another process (in this case your attempt to write to it).
File.Create(string) returns a FileStream object that holds the file open. Even though you are not keeping a reference to FileStream object in a variable, it still exists. The object is eligable for garbage collection, and when that happens the file will be closed, but there is no predicting when the garbage collection will take place.
Is it possible to create a file using the FileStream object in .net, specifying DeleteAfterClose option and allow read access to that file?
I've tried using:
System.IO.FileStream strBMP = new System.IO.FileStream(sFileName, System.IO.FileMode.Create, System.Security.AccessControl.FileSystemRights., System.IO.FileShare.ReadWrite, 1024, System.IO.FileOptions.DeleteOnClose);
but the other object attempting the read gets a file share violation.
I'm trying to do this because I'm creating the file (a tif), and then using a COM object (MODI) to perform OCR on the image. My problem is that eve after I call the close method on the MODI com object, I still can't delete the file using the System.File.Delete method because the MODI com object hasn't quite finsished with it. I thought if I could create my file with the DeleteAfterClose option, and still allow reading on that file I'd be set, I just can't figure out how to get passed the sharing violation - if it is even possible.
When two processes are opening the same file, both of them need to specify compatible sets of file sharing flags for the second open to succeed. Unless you can control the flags being passed by MODI when it opens the file, there's probably no way to avoid the sharing violation; for example, if it attempts to open the file in an exclusive mode, it will always fail if your process has the file open, no matter what flags you pass to the FileStream constructor.
A well-designed COM object (which may or may not be the case here) would not leave files open when it was released, so the problem may be related to the .NET COM interop layer; it's possible that it's keeping some MODI COM objects alive in an unanticipated way. Indeed, threads on other forums about this problem all mention managed code. It's possible that some combination of Marshal.FinalReleaseComObject, GC.Collect, and GC.WaitForPendingFinalizers may help solve the problem, but no one appears to have written up a definitive solution (yet) and using those functions feels extremely hacky and very brittle.
Is there a built in method for waiting for a file to be created in c#? How about waiting for a file to be completely written?
I've baked my own by repeatedly attempting File.OpenRead() on a file until it succeeds (and failing on a timeout), but spinning on a file doesn't seem like the right thing to do. I'm guessing there's a baked-in method in .NET to do this, but I can't find it.
What about using the FileSystemWatcher component ?
This class 'watches' a given directory or file, and can raise events when something (you can define what) has happened.
When creating a file with File.Create you can just call the Close Function.
Like this:
File.Create(savePath).Close();
FileSystemWatcher can notify you when a file is created, deleted, updated, attributes changed etc. It will solve your first issue of waitign for it to be created.
As for waiting for it to be written, when a file is created, you can spin off and start tracking it's size and wait for it stop being updated, then add in a settle time period, You can also try and get an exclusive lock but be careful of locking the file if the other process is also trying to lock it...you could cause unexpected thigns to occur.
FileSysWatcher cannot monitor network paths. In such instances, you manually have to "crawl" the files in a directory -- which can result in the above users error.
Is there an alternative, so that we can be sure we don't open a file before it has been fully written to disk and closed?