How to test if a file is currently being written to
I have an a开发者_如何学编程pplication that must check a folder and read any files that are copied into it. How do I test if a file in that folder is currently being written to? I only want to read files that have had all their data written to them and are closed.
It ain't clean, but it works:
try
{
using (Stream stream = new FileStream("File.txt"))
{
}
}
catch
{
// Check if file is in use (or whatever else went wrong), and do any user communication that you need to
}
I don't particularly like using exceptions as conditions, but as far as I know this is about the easiest and best (and only reliable) way to do this.
Perhaps opening the file exclusively like this -
System.IO.File.Open(PathToFile, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
That could be placed in a loop with a try/catch until its successful.
Catching exception is expensive you should try to use this:
http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.aspx
There's a super clear example on the msdn page. That'll give you nice events on change, created, delete, renamed.
copy the file into the folder and rename when your done catch the rename event and your sure your not reading files that aren't finished yet.
Or you could catch the change events until (this is tricky) they aren't fired anymore.
The only thing I can think of is that a file lock will be put on the file while it is being written to, therefore preventing you from writing to it (throwing a System.IO exception of file being locked by another process), but this is not foolproof. For example, the file could be written to in chunks by opening and closing the file for each chunk.
So you could do this with a try/catch block:
try
{
//opening the file
}
catch(IOException ex)
{
// file is open by another process
}
The file that is written to will typically have write locks on it so if you try to open it for write, you'll fail; but OTOH you may have a process that opens, writes, and closes the file - then repeats. I think the simplest and safest way would be simply to check for files that were written to recently, but not TOO recent (e.g. not in the last 2 seconds or so)
[l.e.] Another point to consider is that if you have a process that writes data in chunck (open-write-close), and you get an exclusive lock for the file (to check that the file is no longer used) - than your external process will fail. I think it's far better to check the timestamps, and only get the exclusive lock after you're reasonably sure that the other process finished writing.
When you open it with System.IO.File.OpenWrite(filename)
, it should throw IOException
.
So, in a try catch, the code being executed in the catch block should tell you the file was open.
Number of options. The one that springs to mind straight away is to try opening the file for write. If you raise an exception, it is still being written to. Wait for a defined period and try again.
Alternatively check the timestamps and only try reading the file 1 or 2 minutes after the timestamp last changed
Use the System.IO.FileSystemWatcher
to determine files that are changed.
Open them in an exclusive reader (FileMode.Read
) in make the copies, and catch the exception should this fail (because someone else has it open for writing).
If you have any control over the process that does the writing in, then consider augmenting it so the following process happens:
- Process starts writing file "filename.xyz"
- Process writes more of file "filename.xyz"
- ....
- ....
- Process finishes writing file "filename.xyz"
- Process writes another (zero-length, empty) file to the folder called "filename.xyz.done"
You can look for ".done" files as the trigger to start processing a file. Again, this will only work if you have any way to modify the process that does the writing in of files.
精彩评论