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);
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.
Let's say I make a long string called 'lotsofdata', and then output its content with this code:
string outputFilePath = #"C:\output.txt";
System.IO.File.WriteAllText(outputFilePath, lotsofdata);
SpecialFunction1();
SpecialFunction2();
SpecialFunction3();
My question is, does the computer completely finish writing all of the stuff to output.txt before moving on to running SpecialFunction1? Or, does it set the outputting process in motion and move on to SpecialFunction1 before the outputting process is complete?
I'm asking because I want to make sure output.txt is done being written to before proceeding to SpecialFunction1() and I don't know how to ensure this.
Simple answer is yes.
The underlying stream is filled and closed (the important bit) before the WriteAllText method exits.
File.WriteAllText Method
Creates a new file, write the contents to the file, and then closes
the file. If the target file already exists, it is overwritten.
http://msdn.microsoft.com/en-us/library/system.io.file.writealltext%28v=vs.110%29.aspx
This is not a golden rule for all file writing. If you were writing directly to a FileStream, you would need to make sure you call Flush or Close (ideally, you should always call Close anyway) if you want to make sure that the file is actually written before continuing.
FileStream.Close Method
Any data previously written to the buffer is copied to the file before
the file stream is closed, so it is not necessary to call Flush before
invoking Close. Following a call to Close, any operations on the file
stream might raise exceptions. After Close has been called once, it
does nothing if called again.
http://msdn.microsoft.com/en-us/library/aa328800%28v=vs.71%29.aspx
The key takeaway for you here is that any operation that flushes a stream will not exit until the data has been written to its destination.
Yes, in the code provided first you will finish with the writing text to the file, and only after will run other SpecialFunction functions.
According to the File.WriteAllText documentation:
The file handle is guaranteed to be closed by this method, even if
exceptions are raised
So you should not have any concurent IO issues even on big files.
System.IO.File.WriteAllText when completes, will flush all the text to the filesystem cache, then, it will be lazily written to the drive.
All happening in the same thread, therefore your file will be written before anything else happens.
I have Following Code in a Page_Load called function. When the Page is loaded the first time after starting Visual Studio, everything works out fine.
But any other opening call to the File after that returns IOException: "File is in use by another process", even when directly opening the File in VisualStudio Solution this Error is returned(of course not as Exception)
FileStream mailinglist_FileStream = new FileStream(#"\foobarFile.txt", FileMode.Open);
PeekingStreamReader mailinglist_Reader = new PeekingStreamReader(mailinglist_FileStream);
//Do some stuff with the file
mailinglist_FileStream.Close();
mailinglist_Reader.Close();
mailinglist_Reader.Dispose();
mailinglist_FileStream.Dispose();
Why is the file still locked? and why does fully restarting Visual Studio reset the File?
when checking file-Properties it says:
Build Action: Content
Copy to output directory: do not Copy
I am only reading this File. can i do something similiar to adLockOptimistic, so that multiple processes can access the File?
Why is the file still locked? and why does fully restarting Visual
Studio reset the File? when checking file-Properties it says [...]
I don't know why the file is still locked: probably because your code fails before the stream is closed/disposed.
About "why fully restarting Visual Studio [...]": because you may be using IIS Express or ASP.NET Dev Server whose are closed when you close the IDE, so locks on files are released since the process holding the locks is no longer running.
And about "why is the file still locked?[...]" it could be because the file stream isn't closed because sometimes the thread may not end successfully and the locks aren't released.
As other answer said, check how using block may avoid that IDisposable objects wouldn't be disposed:
// FileShare.ReadWrite will allow other processes
// to read and write the target file even if other processes
// are working with the same file
using var mailinglist_FileStream = new FileStream(#"\foobarFile.txt", FileMode.Open, FileShare.ReadWrite);
using var mailinglist_Reader = new PeekingStreamReader(mailinglist_FileStream);
// Do your stuff. Using blocks will call Dispose() for
// you even if something goes wrong, as it's equal to a try/finally!
I am only reading this File. can i do something similiar to
adLockOptimistic, so that multiple processes can access the File?
Yes, take a look at File.Open method and FileShare enumeration:
File.Open: http://msdn.microsoft.com/en-us/library/y973b725.aspx
FileShare enum: http://msdn.microsoft.com/en-us/library/system.io.fileshare.aspx
Learn to use using:
using (FileStream fileStream = File.Open(#"C:\somefile", FileMode.Open, FileAccess.Read))
{
...
}
The using construct ensures that the file will be closed when you leave the block even if an exception is thrown.
Your problem might not be here, but somewhere else in your code. You'll have to go through all your code and look for places where you have opened files but not put it inside a using statement.
An old question but unfortunately the given answers can be not applicable to the question.
The problem specifically in Windows lies in two aspects of Windows behavior:
a) when the handle to the file, opened for writing, is closed, the Microsoft Antimalware Service opens the file to check the newly written data for malware;
b) the OS itself keeps the file opened for some time after all handles to it are closed. This time can be from seconds to many minutes depending on the nature of the file and other factors.
We saw this problem many times in our products and had to provide special support for this case - our kernel-mode attempts to close the file as soon as the last handle to it is closed.
Try using using blocks, it may not fix your lock problem, but it is better form for disposable objects.
using (FileStream mailinglist_FileStream = new FileStream(#"\foobarFile.txt", FileMode.Open))
{
using (PeekingStreamReader mailinglist_Reader = new PeekingStreamReader(mailinglist_FileStream))
{
...
}
}
Also, try closing mailinglist_Reader before mailinglist_FileStream.
I am implementing an event handler that must open and process the content of a file created by a third part application over which I have no control. I am warned by a note in "C# 4.0 in a nutshell" (page 495) about the risk to open a file before it is fully populated; so I am wondering how to manage this occurrence. To keep at minimum the load on the event handler, I am considering to have the handler simply insert in a queue the file names and then to have a different thread to manage the processing, but, anyways, how may I make sure that the write is completed and the file read is safe? The file size could be arbitrary.
Some idea? Thanks
A reliable way to achieve what you want might be to use FileSystemWatcher + NTFS USN journal.
Maybe more complicated than you expected, but FileSystemWatcher alone won't tell you for sure that the newly created file has been closed
-first, the FileSystemWatcher, to know when a file is created. From there you have the complete file path, and are 1 or 2 pinvokes away from getting the file unique ID (which can help you to track it during its whole lifetime).
-then, read the USN journal, which tracks everything that occurs on your drive. Filter on entries corresponding to your new file's ID, and read the journal until reaching the entry with the 'Close' event.
From there, unless your file is manipulated in special ways (opened and closed multiple times by the application that generates it), you can assume it is safe to read it and do whatever you wanted to do with it.
A really great C# implementation of an USN journal parser is StCroixSkipper's work, available here:
http://mftscanner.codeplex.com/
If you are interested I can give you more help about USN journal, as I use it in my project.
Our workaround is to watch for a specific extension. When a file is uploaded, the extension is ".tmp". When its done uploading, it's renamed to have the proper extension.
Another alternative is to have the server try to move the file in a try/catch block. If the fie isn't done being uploaded, the attempt to move the file will throw an exception, so we wait and try again.
Realistically, you can't know. If the other applications "write" operation is to open the file denying write access to everyone else then when it's done, close the file. When you get a notification then you could simply open the file requesting write access and if that fails, you know the operation isn't complete. But, if the "write" operation is to open the file, write, close the file, open the file again, and write again, etc., then you're pretty much out of luck.
The best solution I've seen is to set a timer after the last notification. When the timer elapses, try to open the file for write--if you can, assume the "operation" is done and do what you need to do. If the open fails, assume the operation is still in progress and wait some more.
Of course, nothing is foolproof. Despite the above, another operation could start while you're doing what you want with the file and cause interaction problems.
I am developing a tool in c#, at one instance I start writing into a xml file continuously using my tool,when i suddenly restart my machine the particular xml file gets
corrupted, what is the reason an how to avoid it?
xmldocument x= new xmldocument();
x.open();
// change a value of the node every time
x.save();
x=null
this is my code
Use the "safe replace pattern". For example, to replace foo.txt
Write to foo.new
Move foo.txt to foo.old
Move foo.new to foo.txt
Delete foo.old
At any point, you have at least one complete, valid file.
(That helps if you want to write a new file periodically; for appending, I'd go with the answers suggesting that XML isn't the best way forward for you.)
Don't use XML.
XML has a syntax which doesn't lend itself well to writing continuously to the same file, as you always need a final end tag which you can't write unless the file is complete (which it never is with log files, for example).
That means you will always get an invalid XML file when you cancel the writing prematurely (by killing the process or restarting the computer, etc.).
We had a similar situation a while ago and settled on YAML as a nice format which allows for simply appending to the file.
Check that your file is properly closed before the application shuts down.
Also, as someone has pointed out, an XML file must be properly ended with closing tags.
Additional details would also be useful, such as the code that you use to open, write and close the file.
The reason for your file getting corrupted is that due to a crash, you never closed it.
I remember solving an issue like that once, with a file overlapping flag. But that was in C++ using method CreateFile.