Why is File.Create needed to be closed? - c#

The following throws an exception "The process cannot access the file 'D:\MyDir\First.txt' because it is being used by another process."
static void Main(string[] args)
{
Directory.CreateDirectory(#"D:\MyDir");
File.Create(#"D:\MyDir\First.txt");
File.WriteAllText(#"D:\MyDir\First.txt", "StackOverflow.com");
}
However following works:
using (File.Create(#"D:\MyDir\First.txt"))
{
}
or
File.Create(#"D:\MyDir\First.txt").Close();
Why? What in File.Create needs to be closed?

File.Create is doing more than you think here. It's not just creating the file, it's also returning an active stream to the file. However, you're not doing anything with that stream. The using block in your latter example closes that stream by disposing it.
Note also that this is a significant clue about the return value:
File.Create(#"D:\MyDir\First.txt").Close();
(It actually wasn't intuitive to me when I first read your question, but looking back at it this line of code actually says it all.)
Your next step, calling File.WriteAllText also does more than you think. According to the documentation, it:
Creates a new file, writes the specified string to the file, and then closes the file.
So it would seem that your File.Create call isn't really needed here anyway.

Because it opens a file stream, which is a class managing some operating system low-level resources and those must be released in order to let other operations in other threads, and even in other applications, access to the file.

You don't actually need to call File.Create() to then be able to call File.WriteAllText().
File.WriteAllText() will create a new file and write to it then close the file all in one handy method.
If the file already exists it'll be overwritten.

The MSDN docs for File.Create() explain this:
The FileStream object created by this
method has a default FileShare value
of None; no other process or code can
access the created file until the
original file handle is closed.
Basically until the file create is closed the file cannot be access by another process (in this case your attempt to write to it).

File.Create(string) returns a FileStream object that holds the file open. Even though you are not keeping a reference to FileStream object in a variable, it still exists. The object is eligable for garbage collection, and when that happens the file will be closed, but there is no predicting when the garbage collection will take place.

Related

File is being used by another process when using File.WriteAllText

I have some code that saves a string to a file, something like this:
string TheFileJS = HttpRuntime.AppDomainAppPath + "\\SomePath\\" + ClientFileName + ".js";
if (File.Exists(TheFileJS) == true)
{
File.Delete(TheFileJS);
}
File.WriteAllText(TheFileJS, TheJS);
I'm using File.WriteAllText because I thought it would prevent problems with file locking but what's happening is that sometimes I get the error File is being used by another process. The problem is that it rarely happens, but once this exception occurs on a particular file, all client calls to this file then result in a 404.
What do I need to change in my code to make sure this error never happens?
I would imagine that you are running into problems with the lock still being open after the delete causing you to be unable to then rewrite the file.
The good news is that this is easily solvable by not deleting the file first.
From the docs for WriteAllText it says "Creates a new file, writes the specified string to the file, and then closes the file. If the target file already exists, it is overwritten."
What this means is that it effectively deletes the contents of the file anyway so checking if the file exists first is unnecessary. If you are not doing that check then you shouldn't run into any problems.
This is also where exception handling would come in handy. If this is critical code then you could retry or alert an admin immediately of the problem hopefully preventing all your clients then 404ing.
Try this. During file creation, if any stream is opened, it will be closed.
FileStream stream = File.Create(TheFileJS);
stream.Close();

In my C# code does the computer wait until output is complete before moving on?

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.

c# file move and overwrite [duplicate]

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);

Create file with DeleteAfterOpen, and allow other process to read the file

Is it possible to create a file using the FileStream object in .net, specifying DeleteAfterClose option and allow read access to that file?
I've tried using:
System.IO.FileStream strBMP = new System.IO.FileStream(sFileName, System.IO.FileMode.Create, System.Security.AccessControl.FileSystemRights., System.IO.FileShare.ReadWrite, 1024, System.IO.FileOptions.DeleteOnClose);
but the other object attempting the read gets a file share violation.
I'm trying to do this because I'm creating the file (a tif), and then using a COM object (MODI) to perform OCR on the image. My problem is that eve after I call the close method on the MODI com object, I still can't delete the file using the System.File.Delete method because the MODI com object hasn't quite finsished with it. I thought if I could create my file with the DeleteAfterClose option, and still allow reading on that file I'd be set, I just can't figure out how to get passed the sharing violation - if it is even possible.
When two processes are opening the same file, both of them need to specify compatible sets of file sharing flags for the second open to succeed. Unless you can control the flags being passed by MODI when it opens the file, there's probably no way to avoid the sharing violation; for example, if it attempts to open the file in an exclusive mode, it will always fail if your process has the file open, no matter what flags you pass to the FileStream constructor.
A well-designed COM object (which may or may not be the case here) would not leave files open when it was released, so the problem may be related to the .NET COM interop layer; it's possible that it's keeping some MODI COM objects alive in an unanticipated way. Indeed, threads on other forums about this problem all mention managed code. It's possible that some combination of Marshal.FinalReleaseComObject, GC.Collect, and GC.WaitForPendingFinalizers may help solve the problem, but no one appears to have written up a definitive solution (yet) and using those functions feels extremely hacky and very brittle.

.NET: IOException for permissions when creating new file?

I am trying to create a new file and write XML to it:
FileStream output = File.Create(Path.Combine(PATH_TO_DATA_DIR, fileName));
The argument evaluates to:
C:\path\to\Data\test.xml
The exception is:
The process cannot access the file 'C:\path\to\Data\test.xml' because it is being used by another process.
What am I doing wrong here?
UPDATE: This code throws the same exception:
StreamWriter writer = new StreamWriter(Path.Combine(PATH_TO_DATA_DIR, fileName));
UPDATE 2: The file I am trying to create does not exist in the file system. So how can be it in use?
UPDATE 3: Changed to a new file name, and now it works. I'm not sure why. Perhaps I unknowing created it in the first call, and it failed on subsequent calls?
The message means that another process is using that file. If you have it open it could be using it, or when it was originally created if the stream was not closed properly that could do it also.
First check to make sure you do not have it open. I would try to change the fileName and see if you get the same error. If you do get the same error than some place in your code it is not closing a stream that when it is done with the file.
Your program keeps a handle on your file after it's being created to return to your FileStream object. Because you don't specify the access to it, perhaps it won't let you get a grab on it. Perhaps should you consider closing it, and then reopen it in a proper manner by specifying how you want it open (ReadOnly, ReadWrite, WriteOnly) ?
Not trying to sound insulting, but does the folder exist? Does the file already exist but is hidden by the system? And does the user account that is running the program have write permissions to the folder? Have you tried creating a file using a different method (like with File.WriteAllText(<path>, "Testing") just to see if it's your particular call to File.Create?

Categories

Resources