Proper way of waiting until a file is created - c#

I have the following code:
// get location where application data director is located
var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
// create dir if it doesnt exist
var folder = System.IO.Path.Combine(appData, "SomeDir");
if (System.IO.Directory.Exists(folder) == false)
System.IO.Directory.CreateDirectory(folder);
// create file if it doesnt exist
var file = System.IO.Path.Combine(folder, "test.txt");
if(System.IO.File.Exists(file)== false)
System.IO.File.Create(file);
// write something to the file
System.IO.File.AppendAllText(file,"Foo");
This code crashes on the last line (An unhandled exception of type 'System.IO.IOException' occurred in mscorlib.dll). If I put a Thread.Sleep(400) after creating the file the code works great. What is the proper way of waiting until the file is created?
P.S.
I am using .net framework 3.5
Even if I wait it crashes :/

The reason for that is because File.Create is declared as:
public static FileStream Create(
string path
)
It returns a FileStream. The method is supposed to be used to create and open a file for writing. Since you never dispose of the returned FileStream object you're basically placing your bets on the garbage collector to collect that object before you need to rewrite the file.
So, to fix the problem with the naive solution you should dispose of that object:
System.IO.File.Create(file).Dispose();
Now, the gotcha here is that File.AppendAllText will in fact create the file if it does not exist so you don't even need that code, here is your full code with the unnecessary code removed:
// get location where application data director is located
var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
// create dir if it doesnt exist
var folder = System.IO.Path.Combine(appData, "SomeDir");
System.IO.Directory.CreateDirectory(folder);
// write something to the file
var file = System.IO.Path.Combine(folder, "test.txt");
System.IO.File.AppendAllText(file,"Foo");
Directory.CreateDirectory will likewise not crash if the folder already exists so you can safely just call it.

There is no need to create the file if you intend to use File.AppendAllText
About the root cause for the error, and a preferred way to write to files in general:
The file was created, and returned a stream that you didn't use/close. best method should be to use this stream to write to the file.
using (FileStream fs = File.Create(file))
{
fs.Write("What ever you need to write..");
}

Related

rest api output to json file in c# [duplicate]

I have a string with a C# program that I want to write to a file and always overwrite the existing content. If the file isn't there, the program should create a new file instead of throwing an exception.
System.IO.File.WriteAllText (#"D:\path.txt", contents);
If the file exists, this overwrites it.
If the file does not exist, this creates it.
Please make sure you have appropriate privileges to write at the location, otherwise you will get an exception.
Use the File.WriteAllText method. It creates the file if it doesn't exist and overwrites it if it exists.
Generally, FileMode.Create is what you're looking for.
Use the file mode enum to change the File.Open behavior. This works for binary content as well as text.
Since FileMode.Open and FileMode.OpenOrCreate load the existing content to the file stream, if you want to replace the file completely you need to first clear the existing content, if any, before writing to the stream. FileMode.Truncate performs this step automatically
// OriginalFile:
oooooooooooooooooooooooooooooo
// NewFile:
----------------
// Write to file stream with FileMode.Open:
----------------oooooooooooooo
var exists = File.Exists(path);
var fileMode = exists
? FileMode.Truncate // overwrites all of the content of an existing file
: FileMode.CreateNew // creates a new file
using (var destinationStream = File.Open(path, fileMode)
{
await newContentStream.CopyToAsync(destinationStream);
}
FileMode Enum
If your code doesn't require the file to be truncated first, you can use the FileMode.OpenOrCreate to open the filestream, which will create the file if it doesn't exist or open it if it does. You can use the stream to point at the front and start overwriting the existing file?
I'm assuming your using a streams here, there are other ways to write a file.

File.AppendAllText causes access exception to be thrown when program run for the second time

I have a log file that I delete and create every time my application is launched like so:
if (File.Exists(LogPath))
{
File.Delete(LogPath);
File.Create(LogPath);
}
And I'm writing in it using File.AppendAllText like so:
File.AppendAllText(LogPath, logMessage);
My issue is that when I run the program for the second time, the above call causes an exception to be thrown saying file can't be accessed
"because it is being used by another process"
What is wrong with this approach?
It's caused by File.Create(). Remove it and File.AppendAllText creates a new file if it doesn't exist.
Note:
File.Create() returns a FileStream value, if you do not dispose it, then it will cause an error when you want to access it.
This is not because of File.AppendAllText but instead this line of code:
File.Create(LogPath);
As per the documentation of File.Create(string):
Return Value
Type: System.IO.FileStream
A FileStream that provides read/write access to the file specified in path.
It returns an open FileStream object. You need to dispose of this object in order to close the stream and release the file. If you don't then this object will keep the file open until GC finalizes the object at some later indeterminate point in time.
Here's how to write this line of code, either one of the following two alternatives will work:
File.Create(LogPath).Dispose();
using (File.Create(LogPath)) { }
What happened is that the second time your program ran the file exists, so you deleted it and then recreated it, but the "recreated it" part kept the file open, so when it a short time later reached the File.AppendAllText method, the file was still open.
Note: If you always call File.AppendAllText you can simply just delete it, as AppendAllText will create the file if it doesn't already exist, as per the documentation of File.AppendAllText:
Opens a file, appends the specified string to the file, and then closes the file. If the file does not exist, this method creates a file, writes the specified string to the file, then closes the file.
(my emphasis)
You would need to close the file after you create for further processing.
if (File.Exists(LogPath))
{
File.Delete(LogPath);
using(var handler = File.Create(LogPath))
{
}
}
Other way could be to use WriteAllText and you won't need to delete it everytime.
File.WriteAllText(LogPath, "contents");
You, probably, mean
// clear the file (write an empty text to it) if it exists
if (File.Exists(LogPath))
{
File.WriteAllText(LogPath, "");
}
...
File.AppendAllText(LogPath, logMessage);
you can try combining clearing and writing in one call:
File.WriteAllText(LogPath, logMessage);
If the file exists, WriteAllText will clear it and write logMessage; if file doesn't exist, WriteAllText will create it and write logMessage.

The file is being used by another process, I must close it? How?

I am using a text file to have some data there for later purposes. So what I do is to check if file exists, if not I am creating a new file when I need. This gives me error saying that my file is still being used by a different process, but I'm not sure why that is.
This is how I do it. Here, I am checking if file exists which starts when program runs:
private void CreateLastOpenFile()
{
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
if (!File.Exists(file))
{
File.Create(file);
}
}
Now, I am adding some data to it while checking or creating a new file (I am having this in 2 places in my program):
CreateLastOpenFile();
File.WriteAllText(file, data);
What could be wrong here? I have read some examples from the Net, but didn't see anything about closing any files.
Try this. This will close the opened stream during file creation
if (!File.Exists(file))
{
FileStream str = File.Create(file);
str.Close();
}
File.Create is creating a FileStream that locks the file. You should close it. Actually, you don't even need to create a file. File.WriteAlltext will do it for you
You are not closing the stream handle that File.Create() returns.
Suggest you do not use File.Create() in your case. You can just use File.WriteAllText(file, data); - according to MSDN documentation it creates the file if it doesn't exist or overwrites the contents when file exists. After that closes the file stream.
I recommend you to create and fill with data the file in one step, using some class like StreamWriter that allows you to dispose the class, you should not have problem doing it this way, here is an example:
StreamWriter Swr = new StreamWriter(FilePath);
Swr.Write(Data);
Swr.Close();
Swr.Dispose();
//Doing the close and Dispose you get sure the file is not locked anymore
You can also use File.WriteAllText(string Path, string Data), this method does not lock the file.
If you are using below method to write the data into text file, you dont need to check if file exists and if not create it. "WriteAllText" takes cares of all these things by itself. It will create the file if not exists, write the data and close it, or overwrite the file if already exists.
File.WriteAllText(file, data);
if you are using writeAllText() or readAllText() method than close() method is not used as they closed file after reading or writing(above methods)

Deploy an application's xml file with installer or create it on the fly if it does not exist

I am having an xml file like:
<CurrentProject>
// Elements like
// last opened project file to reopen it when app starts
// and more global project independend settings
</CurrentProject>
Now I asked myself wether I should deliver this xml file with above empty elements with the installer for my app or should I create this file on the fly on application start if it does not exist else read the values from it.
Consider also that the user could delete this file and that should my application not prevent from working anymore.
What is better and why?
UPDATE:
What I did felt ok for me so I post my code here :) It just creates the xml + structure on the fly with some security checks...
public ProjectService(IProjectDataProvider provider)
{
_provider = provider;
string applicationPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
_projectPath = Path.Combine(applicationPath,#"TBM\Settings.XML");
if (!File.Exists(_projectPath))
{
string dirPath = Path.Combine(applicationPath, #"TBM");
if (!Directory.Exists(dirPath))
Directory.CreateDirectory(dirPath);
using (var stream = File.Create(_projectPath))
{
XElement projectElement = new XElement("Project");
projectElement.Add(new XElement("DatabasePath"));
projectElement.Save(stream, SaveOptions.DisableFormatting);
}
}
}
In a similar scenario, I recently went for creating the initial file on the fly. The main reason I chose this was the fact that I wasn't depending on this file being there and being valid. As this was a file that's often read from/written to, there's a chance that it could get corrupted (e.g. if the power is lost while the file is being written).
In my code I attempted to open this file for reading and then read the data. If anywhere during these steps I encountered an error, I simply recreated the file with default values and displayed a corresponding message to the user.

How do I create directory if it doesn't exist to create a file?

I have a piece of code here that breaks if the directory doesn't exist:
System.IO.File.WriteAllText(filePath, content);
In one line (or a few lines), is it possible to check if the directory leading to the new file doesn't exist and if not, to create it before creating the new file?
I'm using .NET 3.5.
To Create
(new FileInfo(filePath)).Directory.Create() before writing to the file.
....Or, if it exists, then create (else do nothing)
System.IO.FileInfo file = new System.IO.FileInfo(filePath);
file.Directory.Create(); // If the directory already exists, this method does nothing.
System.IO.File.WriteAllText(file.FullName, content);
You can use following code
DirectoryInfo di = Directory.CreateDirectory(path);
As #hitec said, you have to be sure that you have the right permissions, if you do, you can use this line to ensure the existence of the directory:
Directory.CreateDirectory(Path.GetDirectoryName(filePath))
An elegant way to move your file to an nonexistent directory is to create the following extension to native FileInfo class:
public static class FileInfoExtension
{
//second parameter is need to avoid collision with native MoveTo
public static void MoveTo(this FileInfo file, string destination, bool autoCreateDirectory) {
if (autoCreateDirectory)
{
var destinationDirectory = new DirectoryInfo(Path.GetDirectoryName(destination));
if (!destinationDirectory.Exists)
destinationDirectory.Create();
}
file.MoveTo(destination);
}
}
Then use brand new MoveTo extension:
using <namespace of FileInfoExtension>;
...
new FileInfo("some path")
.MoveTo("target path",true);
Check Methods extension documentation.
You can use File.Exists to check if the file exists and create it using File.Create if required. Make sure you check if you have access to create files at that location.
Once you are certain that the file exists, you can write to it safely. Though as a precaution, you should put your code into a try...catch block and catch for the exceptions that function is likely to raise if things don't go exactly as planned.
Additional information for basic file I/O concepts.
var filePath = context.Server.MapPath(Convert.ToString(ConfigurationManager.AppSettings["ErrorLogFile"]));
var file = new FileInfo(filePath);
file.Directory.Create(); If the directory already exists, this method does nothing.
var sw = new StreamWriter(filePath, true);
sw.WriteLine(Enter your message here);
sw.Close();

Categories