views:

260

answers:

4

I'm trying to download a file from the web and save it locally, but I get an exception:

C# The process cannot access the file 'blah' because it is being used by another process.

This is my code:

File.Create("data.csv");  // create the file
request = (HttpWebRequest)WebRequest.CreateDefault(new Uri(url));
request.Timeout = 30000;
response = (HttpWebResponse)request.GetResponse();

using (Stream file = File.OpenWrite("data.csv"), // <-- Exception here
    input = response.GetResponseStream())
{
    // Save the file using Jon Skeet's CopyStream method
    CopyStream(input, file);
}

I've seen numerous other questions with the same exception, but none of them seem to apply here. Any help?

Update:
Thanks for the answers! Removing the File.Create(...) fixed it!

One comment on the documentation of OpenWrite: it is a little misleading, the brief description says:

Opens an existing file for writing.

The detailed description says:

If the file exists, it is opened for writing at the beginning. The existing file is not truncated.

Update 2.0:
It looks like the discrepancy is between IntelliSense/F1 and the online documentation. I thought it should be the same since I allow F1 to connect to the web when it's displaying documentation.

+10  A: 

File.Create returns a FileStream - which you're not closing. That means you won't be able to open another stream writing to the same file until the finalizer has closed the existing stream.

Just get rid of the call to File.Create - File.OpenWrite will create it anyway. Alternatively, keep the FileStream around to write to:

using (Stream file = File.Create("data.csv"))
{
    request = (HttpWebRequest)WebRequest.CreateDefault(new Uri(url));
    request.Timeout = 30000;
    using (var response = (HttpWebResponse)request.GetResponse())
    using (Stream input = response.GetResponseStream())
    {
        // Save the file using Jon Skeet's CopyStream method
        CopyStream(input, file);
    }
}

Note that I'm also disposing of the WebResponse here, which you should do to make sure the connection is freed to the connection pool.

Jon Skeet
@Jon, thanks that worked... I got confused because of the documentation: "**If the file exists**, it is opened for writing at the beginning. The existing file is not truncated."
Lirik
@Lirik: It's opened either way - but the fact that it's not truncated is nasty, I hadn't spotted that. In that case you *probably* want to use `File.Create` but get rid of the `File.OpenWrite` call - the code I've included in the answer should be fine.
Jon Skeet
@Jon thank you... Do you have any comments on the documentation of OpenWrite? It seems like it's a little unclear.
Lirik
@Lirik: It seems reasonably clear. It's already stated that it "Opens an existing file or creates a new file for writing." It's just clarifying what exactly happens in the situation where the file already exists. It's not trying to say that if it doesn't already exist it *isn't* opened for writing.
Jon Skeet
@Jon, it looks like there is a mismatch with the documentation when I press F1 on OpenWrite through Visual Studio 2008 (I allow it to connect to the internet when it pulls up the help files). The online documentation does say that it also creates a new file for writing, but not the F1 documentation through VS 2008. Is there a "good" reason for this behavior?
Lirik
@Jon btw, I get the same (incomplete) documentation with IntelliSense.
Lirik
@Lirik The wacky thing about F1 documentation is it can 1) give you older versions of the documentation that may contain bugs 2) Give you documentation for a version of the .NET framework that you are not targetting 3) Give you documentation for a function of the same name in a different object. More than one class can have a OpenWrite function in .NET. There is a drop down menu in the F1 documentation that allows you to select from all the implementations of that function name which one you intended. It seems to NOT be smart enough to pick this based on the context of the F1.
AaronLS
+1  A: 

First. File.Create will return a stream that you should use for accessing the file.

Second, if that doesn't resolve the issue, if you google who lock you will find a program that let's you determine what process is accessing a file at the same time.

AaronLS
+4  A: 

looks like File.Create returns an open FileStream object

http://msdn.microsoft.com/en-us/library/aa328775(v=VS.71).aspx

try

using (FileStream fs = File.Create("data.csv"))

and leave off the first File.Create

house9
+1  A: 

The problem is that the File.Create method actually opens the file and returns a FileStream object. It won't close the file until the object is garbage collected (which will happen at an indeterminate time). The FileStream object still gets created, regardless of whether or not you use it. Try this:

using (Stream file = File.Create("data.csv"),
    input = response.GetResponseStream()) 
{ 
    // Save the file using Jon Skeet's CopyStream method 
    CopyStream(input, file); 
} 
Peter Ruderman