[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

microsoft.public.dotnet.framework

File.WriteAllText fails: "file is being used by another process"

Ihor Bobak

9/8/2008 7:19:00 PM

Hello, everybody.

We get strange error with File.WriteAllText(), and I cannot understand why.
The stack trace is the following:

Message: The process cannot access the file
'C:\WINDOWS\TEMP\_633558601793472408_2003786287.tmp.xml' because it is being
used by another process.
Type: System.IO.IOException
Stack Trace:
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess
access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize,
FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean
bFromProxy)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess
access, FileShare share, Int32 bufferSize, FileOptions options)
at System.IO.StreamWriter.CreateFile(String path, Boolean append)
at System.IO.StreamWriter..ctor(String path, Boolean append, Encoding
encoding, Int32 bufferSize)
at System.IO.StreamWriter..ctor(String path, Boolean append, Encoding
encoding)
at System.IO.File.WriteAllText(String path, String contents, Encoding
encoding)
at FrameworkBase.Log.DataPortal.LogDataPortalTargetEmail.Write(ArrayList
aLogRecords)

I am on 100% sure that the file has UNIQUE name and cannot definitely be
used by any other piece of code or any other application.

Look how it works. We have a "FileTemp" class which is responsible for
generation of the temporary file names:

public class FileTemp
{
private const string _underscore = "_";

public static string Get()
{
return Get(string.Empty, ".tmp");
}
public static string Get(string aPrefix, string aExtension)
{
string path = Path.GetTempPath();
Random random = new Random();
string filename;
int count = 0;
do
{
++count;
filename = path + StringUtils.StringSuffixForce(aPrefix, "_") +
DateTime.Now.Ticks.ToString() + "_" + random.Next() +
StringUtils.StringPrefixForce(aExtension, ".");
}
while (count < 100 && File.Exists(filename));
if (count == 100)
throw new ExceptionFramework("Cannot generate filename after 100
attempts. Something impossible...", ExceptionKind.ekDeveloper);
return filename;
}
}

when it generates a name, it checks it's uniqueness. If after 100 attempts
it cannot generate it, it fails with our exception. BUT WE NEVER GOT IT
FAILED SINCE WE EXIST. And neither it failed this time.

Next, the code with File.WriteAllText is the following:

string xmlFileName = FileTemp.Get() + ".xml";
// ... here we build stringWriter - nothing to do with the file
File.WriteAllText(xmlFileName, stringWriter.ToString(), Encoding.UTF8);

As I have proven, xmlFileName has unique file name (otherwise FileTemp.Get()
would fail, but it did not).

Question: why File.WriteAllText produces System.IO.IOException "The process
cannot access the file
'C:\WINDOWS\TEMP\_633558601793472408_2003786287.tmp.xml' because it is being
used by another process." ?

..NET 2.0, Windows XP SP2, windows forms application

Please, help wiith any ideas.


--
Best regards,
Ihor.
4 Answers

Peter Duniho

9/8/2008 10:50:00 PM

0

On Mon, 08 Sep 2008 12:19:01 -0700, Ihor Bobak <ibobak@newsgroup.nospam>
wrote:

> [...]
> Next, the code with File.WriteAllText is the following:
>
> string xmlFileName = FileTemp.Get() + ".xml";
> // ... here we build stringWriter - nothing to do with the file
> File.WriteAllText(xmlFileName, stringWriter.ToString(), Encoding.UTF8);
>
> As I have proven, xmlFileName has unique file name (otherwise
> FileTemp.Get()
> would fail, but it did not).

All due respect, you've proven nothing.

You return the filename before you've actually created and opened with
exclusive access the file, and then you proceed to do things unrelated to
the file. That gives other processes (or even your own, if you're running
multiple threads) plenty of time to create and lock a file with the same
name. Even if you didn't do all that extra work though, you can't ensure
100% lack of conflicts with the strategy you're currently using.

You can't rely on File.Exists() to tell you whether the name you generated
will be safe. Just because it returns true doesn't mean that a
millisecond later, a file that didn't exist won't all of the sudden exist.

IMHO, you would probably be better off either using a naming scheme that
doesn't rely on generating random numbers but rather instead used
something unique about the data being written that ensures unique
filenames, or use the Path.GetTempFileName() method.

Barring doing either of those things, you should fix your "FileTemp.Get()"
method so that rather than checking File.Exists(), simply tries to create
the file in question and doesn't return until it's successfully done so
(make sure you use FileMode.CreateNew to ensure that the file you've
opened is really yours). For best results, just return the FileStream for
the file, rather than the actual name.

Pete

Ihor Bobak

9/9/2008 6:27:00 AM

0

I can agree with only one thing - to return file stream instead of file name.
For this advice thank you very much.

But as to the multiple threads accessing the file - believe me, there can be
no such threads (I did not show all code, but there is a lock). As to the
file name, it WILL be unique. As to the Path.GetTempFileName() - it is buggy,
we've faced with the fact that it generates NOT unique names (this was the
reason why we made our own FileTemp).


--
Best regards,
Ihor.


"Peter Duniho" wrote:

> On Mon, 08 Sep 2008 12:19:01 -0700, Ihor Bobak <ibobak@newsgroup.nospam>
> wrote:
>
> > [...]
> > Next, the code with File.WriteAllText is the following:
> >
> > string xmlFileName = FileTemp.Get() + ".xml";
> > // ... here we build stringWriter - nothing to do with the file
> > File.WriteAllText(xmlFileName, stringWriter.ToString(), Encoding.UTF8);
> >
> > As I have proven, xmlFileName has unique file name (otherwise
> > FileTemp.Get()
> > would fail, but it did not).
>
> All due respect, you've proven nothing.
>
> You return the filename before you've actually created and opened with
> exclusive access the file, and then you proceed to do things unrelated to
> the file. That gives other processes (or even your own, if you're running
> multiple threads) plenty of time to create and lock a file with the same
> name. Even if you didn't do all that extra work though, you can't ensure
> 100% lack of conflicts with the strategy you're currently using.
>
> You can't rely on File.Exists() to tell you whether the name you generated
> will be safe. Just because it returns true doesn't mean that a
> millisecond later, a file that didn't exist won't all of the sudden exist.
>
> IMHO, you would probably be better off either using a naming scheme that
> doesn't rely on generating random numbers but rather instead used
> something unique about the data being written that ensures unique
> filenames, or use the Path.GetTempFileName() method.
>
> Barring doing either of those things, you should fix your "FileTemp.Get()"
> method so that rather than checking File.Exists(), simply tries to create
> the file in question and doesn't return until it's successfully done so
> (make sure you use FileMode.CreateNew to ensure that the file you've
> opened is really yours). For best results, just return the FileStream for
> the file, rather than the actual name.
>
> Pete
>

Peter Duniho

9/9/2008 6:34:00 AM

0

On Mon, 08 Sep 2008 23:27:01 -0700, Ihor Bobak <ibobak@newsgroup.nospam>
wrote:

> I can agree with only one thing - to return file stream instead of file
> name.
> For this advice thank you very much.
>
> But as to the multiple threads accessing the file - believe me, there
> can be
> no such threads (I did not show all code, but there is a lock). As to the
> file name, it WILL be unique. [...]

There is no such guarantee. In practice, it may be unique the vast
majority of times, but there's nothing about your code posted that
provides a provable guarantee of that. And the fact that you occasionally
get an error is sufficient counter-proof.

Pete

jetan

9/9/2008 8:19:00 AM

0

Hi Ihor,

I agree with Peter that there is no 100% guaranteefor race condition issue.
The race condition may be pretty rare, but it is not impossible. I remember
hearing a debugging story from Mark Russinovich's blog that a file is
unexpected locked by Windows Defender application code. This type of race
condition is hard to test. Avoid it at the design&code time is the best
option.

I am not sure if this temp file is locked by the thread in your application
or another application. Can this problem be reproduced 100% or does it
occur occasionally? You may also try to use Process Explorer to search the
locking file name in all the processes at the time of the problem. This may
reveal the locking process.

Thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
=========================================
Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
msdnmg@microsoft.com.

This posting is provided "AS IS" with no warranties, and confers no rights.