Checking if file being accessed

T

tshad

I am trying to get access to a file that may still being written because the
file is so large (7-10MB).


I get an error:

The process cannot access the file 'c:\TestDocs\XMLFiles\492172.XML' because
it is being used by another process


This is when doing:

CheckFileBeingUsed(xmlFile); // below - should give me up to 15
seconds to finish writing the file
fs = new FileStream(xmlFile, FileMode.Open, System.IO.FileAccess.Read);

I tried the following routine which should get an error if still in use. It
should run for 15 seconds (5 * 3), but even though the file is being
accessed (which I know because the FileStream error happens after the call),
it jumps out after the first call and never does go to the catch.

Why is this?
**********************************************
public bool CheckFileBeingUsed(string fileName)
{
// Check to see if file is in use. If very large it may be.

bool inUse = false;
for (int i = 0; i < 5; i++)
{
try
{
System.IO.File.Open(fileName, FileMode.Open,
System.IO.FileAccess.Read, FileShare.None);
inUse = false;
break;
}
catch (System.IO.IOException exp)
{
inUse = true;
System.Threading.Thread.Sleep(3000); // Wait 3
seconds and try again
}

}
return inUse;
}
**********************************************

Thanks,

Tom
 
T

tshad

Peter said:
I don't understand this comment. The method you posted will not
return until it's given up or has opened the file itself. Either
way, how does that "give me up to 15 seconds to finish writing the
file"?

What is happening here is I am going to process this xml file that has lots
of images in it and is very large.

I am getting it too quick and I need to make the file has been completely
written and closed (so I don't get the file being accessed message) before I
start processing it.

The 15 seconds (probably not enough in some cases) is the 3 second delay for
5 loops. If I can access it right away, there would be no delay.

The problem is that the file is being written to and I am trying to open it
exclusively (FileShare.none). If someone already has it open (only when
being put in the folder), the this should give me an error and go to the
catch area. I assume that is how this is supposed to work (got the code
elsewhere).

But as you say later, I should just put the loop and try/catch around the
FileStream call, then when it becomes available I will already have it.
But, really...that doesn't matter. The important part is the rest of
the discussion:


The file is being accessed because you just opened it.

Hopefully, this helps illustrate the fallacy behind your approach. Don't
open a file just to check to see if you can open. Just try to
open it to _use_ it! In addition to the specific problem, the code
you posted also won't work because between the time you think you've
determined whether the file can be opened or not, the status of the
file could change. Most unhelpfully, you could find the file
available, but then it could become unavailable by the time you get
to try to open it.

In my case, this wouldn't happen. I am watching the folder with a
filewatcher Service and the only access would be the person dropping the
file in my folder and my accessing it.
If you want to include some sort of retry logic, so that you can
gracefully deal with situations where something else might also be
using the file, then do so. But once you've successfully opened the
file, just use the opened file. Anything less is just pointless
file-twiddling.

Probably right.

I am still curious as to why the FileShare.none wouldn't create an error, if
the file were still being written to.

Thanks,

Tom
 
B

Bjørn Brox

tshad wrote:
....
I am getting it too quick and I need to make the file has been completely
written and closed (so I don't get the file being accessed message) before I
start processing it.
The simple solution to ensure that the file is complete before it is
used is to store it with a temporary name and rename it to the final
filename when finished.


String tmp_filename = filename + ".tmp";
....
if (File.Exists(filename))
File.Delete(filename);
File.Move(tmp_filename, filename);
 
P

Peter Bromberg [C# MVP]

I've seen this come up so many times. Congratulations on the first
common-sense, simple and logical solution I believe I've seen.
--Peter
 
T

tshad

Bjørn Brox said:
tshad wrote:
...
The simple solution to ensure that the file is complete before it is used
is to store it with a temporary name and rename it to the final filename
when finished.


String tmp_filename = filename + ".tmp";
...
if (File.Exists(filename))
File.Delete(filename);
File.Move(tmp_filename, filename);

Not sure how this would work.

Does it stop at the File.Exists until it is finished copying?

Thanks,

Tom
 
T

tshad

Peter Duniho said:
Huh. Actually, Bjørn's proposal is reasonably common. But I had the
impression from the OP that he doesn't have the luxury of picking the
filename for whatever output's the file.

Correct.

I am not picking the file name.

The user is putting a file into a folder I am watching with my Windows
Service program. It can be anything.

As soon as my FileWatcher program sees the file, it starts to process it.

Thanks,

Tom
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top