Does File.WriteAllText really throws a FileNotFoundException? - c#

Documentation says:
// Summary:
// 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.
First line, first sentence: Creates a new file, and on the exceptions it lists:
// System.IO.FileNotFoundException:
// The file specified in path was not found.
In which case would this happen? If it always create a file then it shouldn't thrown a FileNotFoundException...
Is the documentation wrong? Or is it missing a <remarks> tag perhaps?

File.WriteAllText eventually calls:
private static void InternalWriteAllText(string path, string contents, Encoding encoding)
{
using (StreamWriter streamWriter = new StreamWriter(path, false, encoding))
{
streamWriter.Write(contents);
}
}
All of the exceptions thrown prior to the call to InternalWriteAllText throw ArgumentException or ArgumentNullException but theoretically (since FileStream can throw the exception) the streamWriter.Write(contents); could potentially throw the exception. Very unlikely though based on what it does and how the streamWriter is opened.
I wouldn't necessarily say the doc is wrong per se, more that MS is covering their butt by documenting the (very rare) possibility.
Source: Decompiling mscorlib v4.0.0.0 using ILSpy.
UPDATE
Just checked mscorlib v2.0.0.0, same case except it contains fewer sanity checks (meaning it basically translates directly to the code above).

Related

Exception thrown when starting StreamWriter

Every 24 hours, my code auto-generates a .csv-file, writes it temporarily to an Azure directory, and finally deletes it after operating on it.
It succeeds, but from the logs I can see, that an exception is thrown.
Exception:
"The process cannot access the file 'D:\home\site\wwwroot\myFile.csv'
because it is being used by another process."
The log points to these two lines of code, where I simply specify the directory and file-name and then start a StreamWriter:
string filePath = Environment.CurrentDirectory + "\\myFile.csv"; //Specify where to create csv on hosted Azure server (not locally)
using (var w = new StreamWriter(filePath, false, new UTF8Encoding(false))) //Exception is thrown here
{
//more code
}
I am very confused, how the two above lines can result in that exception, especially since the file is always deleted after upload.
For my particular case, the problem was that the StreamWriter code was executed twice, instead of the intended once. Thanks to user TheGeneral for guiding me in the right direction in the comments.

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.

NotSupportedException gets thrown

I am using C# to create a function to write data to a file in File System, and reate it and repeat function if file doesn't exist.
The first method of just writing the data is working. But the second method, if the file is not present and the program has to first create it, isn't working. It creates the file but at the very same time throws an exception to me in Visual Studio saying
System.NotSupportedException is unhandled
I am using the exact copy of code that the MSDN is having.
http://msdn.microsoft.com/en-us/library/d62kzs03(v=vs.110).aspx
Here is what I am using in my second code block,
// Create file!
using (FileStream fs = File.Create(file))
{
Byte[] info = new UTF8Encoding(true).GetBytes("some text in the file.");
// Add some information to the file.
fs.Write(info, 0, info.Length);
}
// Continue again with the request.
createFile(file);
The method declaration (if required) is as
private static void createFile (string fileName) {
string file = "C:\\Users\\AfzaalAhmad\\Documents\\" + fileName + ".txt";
/* two methods here */
}
The Image is as: (Note that there is no error in the path of file) I have used
Console.Write(file); // to get the path, and its OK!
See it in the image below ↓
Please note, that it does create the file in the Documents folder. But throws this exception. What am I doing wrong here?
Note the detail in the exception report: "The given path's format is not supported."
Also look at the contents of your variable file - it appears to be #"C:\Users\AfzaalAhmad\Documents\C:\Users..." - i.e. it contains the path twice.
So even though the operating system might have managed somehow to create some sort of file, the filename does not contain a valid value.
[edit] createFile(file); and Console.Write(file); are both taking the value #"C:\Users\AfzaalAhmad\Documents\dsg b.txt" but your method createFile is then adding the path a second time. Change it to simply:
private static void createFile (string file) {
/* two methods here */
}
Please have a exact look at the Exception message and the value of your file variable! There is your error!

UnauthorizedAccessException StreamWriter

I have the following code:
public WriteToFile(string path, List<string> text)
{
File.Delete(path);
using (TextWriter writer = new StreamWriter(path, true))
{
foreach(string t in text)
{
writer.WriteLine(text);
}
}
}
Most of the time it works fine, the file is deleted and then created again with the text inside. However every so often the using statement throws an UnauthorizedAccessException. Any idea why? I have admin rights and the program is run as admin.
This is normal, it became undiagnosable because you used File.Delete(). Which is unnecessary, just use the StreamWriter(string) constructor.
This goes wrong because deleting a file doesn't provide a guarantee that the file will actually be deleted. It may be opened by another process. Which has opened the file with delete sharing, programs like virus scanners and file indexers commonly do this. Which makes the Delete() call succeed but the file doesn't disappear until all handles on the file are closed. You got the UnauthorizedAccessException exception because the file didn't get deleted yet.
Get ahead by removing the File.Delete() call. You still need to assume that the StreamReader() constructor can fail. Less often, it is bound to happen sooner or later. You'll get a better exception message. Such are the vagaries of a multi-tasking operating system.

XmlSerializer.Serialize doesn't save a file and doesn't throw an exception

I am having problem with saving of my object. Take a look at this code:
public void SerializeToXML(String FileName)
{
XmlSerializer fSerializer = new XmlSerializer(typeof(Configuration));
using (Stream fStream = new FileStream(FileName, FileMode.Create, FileAccess.Write, FileShare.None))
{
fSerializer.Serialize(fStream, this);
}
}
The problem is that when the user does not have rights to the location on hard disk, this function will not throw me any exception and do not save my file. For example saving to "C:\test.xml" act like nothing happened. And I would like to know if the file has not been saved and it would be good to know the reason why.
I know that I could check if the file on given location exists and throw an exception manualy but shouldn't this be done by the XmlSerializer or FileStream itself?
Thanks for your time
Edit:
As I was suspecting I had to turn on some additional debugging. Since I am using the using clause, the "Enable unmanaged code debugging option" must be check in project properties under the Debug section. After this, the exception is shown in the debugging process.
Edit2
Replacing the above using clause with this code triggers the exception:
public void SerializeToXML(String FileName)
{
XmlSerializer fSerializer = new XmlSerializer(typeof(Configuration));
Stream fStream = new FileStream(FileName, FileMode.Create, FileAccess.Write, FileShare.None);
try
{
fSerializer.Serialize(fStream, this);
}
finally
{
fStream.Close();
}
}
That sounds very strange to me - and it doesn't sound like it has anything to do with the serializer. If you don't have access rights to a particular location, then creating the FileStream should throw an exception; it shouldn't wait until the Serialize line.
Are you absolutely sure that you don't have some catch block higher up which is hiding the problem from you?
I suspect that it has to do with your using statement, because it uses a hidden try-finally construction (where the Dispose() method is called in the finally clause). Information about exceptions which are not visible outside the using block can be found here.
Try replacing the using statement by an instantiation and a call to it's Dispose() method, and I think your problem is solved. Of course, you should afterwards enclose your code in an explicit try-finally structure as part of good programming practice.
Vista file redirection can explain this. It is a feature to allow legacy programs that don't handle UAC properly to still operate. The file gets redirected to the virtual store.
This will happen when you use Visual Studio 2005 or earlier or did something to prevent the manifest from getting embedded in the exe. Fix it by including a manifest.

Categories