Best way to handle errors when opening file - c#

Handling files (opening) is an activity particularly prone to error.
If you were to write a function to do this (although trivial), what is the best way to write it in wrt handling errors?
Is the following good?
if (File.Exists(path))
{
using (Streamwriter ....)
{ // write code }
}
else
// throw error if exceptional else report to user
Would the above (although not syntactially correct) a good way to do this?

Accessing external resources is always prone to error. Use a try catch block to manage the access to file system and to manage the exception handling (path/file existence, file access permissions and so on)

First you can verify if you have access to the file, after, if the file exists and between the creation of the stream use a try catch block, look:
public bool HasDirectoryAccess(FileSystemRights fileSystemRights, string directoryPath)
{
DirectorySecurity directorySecurity = Directory.GetAccessControl(directoryPath);
foreach (FileSystemAccessRule rule in directorySecurity.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount)))
{
if ((rule.FileSystemRights & fileSystemRights) != 0)
{
return true;
}
}
return false;
}
So:
if (this.HasDirectoryAccess(FileSystemRights.Read, path)
{
if (File.Exists(path))
{
try
{
using (Streamwriter ....)
{
// write code
}
}
catch (Exception ex)
{
// throw error if exceptional else report to user or treat it
}
}
else
{
// throw error if exceptional else report to user
}
}
Or you can verify all things with the try catch, and create the stream inside the try catch.

You can use something like this
private bool CanAccessFile(string FileName)
{
try
{
var fileToRead = new FileInfo(FileName);
FileStream f = fileToRead.Open(FileMode.Open, FileAccess.Read, FileShare.None);
/*
* Since the file is opened now close it and we can access it
*/
f.Close();
return true;
}
catch (Exception ex)
{
Debug.WriteLine("Cannot open " + FileName + " for reading. Exception raised - " + ex.Message);
}
return false;
}

Related

Get the message of manually thrown exception

I'm deliberately throwing an exception for a particular scenario, but I would implicitly like to get the error message in string format. I'm aware that one of the overloads for the following exception is string message, but how do I access that string?
Here is the relevant snippet:
string errMsg;
private void Compress()
{
if (sourcePath.EndsWith(".zip"))
{
throw new FileLoadException
("File already compressed. Unzip the file and try again.");
errMsg = //I want the above string here
}
}
Do you mean this:?
try
{
throw new FileLoadException
("File already compressed. Unzip the file and try again.");
}
catch (Exception ex)
{
errMsg = ex.GetBaseException().Message;
}
You can't access the string THERE I'll explain a bit there:
string errMsg;
private void Compress()
{
if (sourcePath.EndsWith(".zip"))
{
throw new FileLoadException
("File already compressed. Unzip the file and try again.");
// The following line is unreachable as the throw ends the function and gets the exception to the calling function as there is no try catch block to catch the exception.
errMsg = //I want the above string here
}
}
A possibility would be to try/catch the exception in the method where you want to set the variable:
private void Compress()
{
if (sourcePath.EndsWith(".zip"))
{
try
{
throw new FileLoadException
("File already compressed. Unzip the file and try again.");
}
catch (Exception e)
{
errMsg = e.Message;
}
}
}
Or to catch the exception in the calling method instead:
try
{
Compress();
}
catch (Exception e)
{
}
regardless of method used the e.Message gives you the message of the exception as a string.
There is no point to try catch the exception and set the message. Unless you re-throw it
try
{
throw new FileLoadException("File already compressed. Unzip the file and try again.");
}
catch (Exception ex)
{
errMsg = ex.GetBaseException().Message;
throw;
}
I would rather do this
private void Compress()
{
if (sourcePath.EndsWith(".zip"))
{
errMsg = "File already compressed. Unzip the file and try again.";
return;
}
}
Not sure I 100% understand but if you want the message from that exception you can catch it and examine the Exception.Message
try
{
throw new FileLoadException("Custom error string");
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
}
here should be an solution for you :)
if (sourcePath.EndsWith(".zip"))
{
FileLoadException ex = new FileLoadException("File already compressed. Unzip the file and try again.");
errMsg = ex.ToString();
}
Console.WriteLine(errMsg);
To throw the exception that you made I would do soemthing like this
static string sourcePath = "test.zip"; //hardcoded file
static string errMsg; //the error string
private static void Compress()
{
try
{
if (!sourcePath.EndsWith(".zip"))
{
Console.WriteLine("File doesn't end with zip so it can be compressed"); //if it does not end with zip its rdy for compressing and here you can indput your code to compress
}
else
{
throw new Exception(); //instead of using try catch you can also generate the code in here instead of throwing an exception.
//when throwing a new exception you make it stop the if setting and jump into the catch if you use break it wont enter the catch but instead it will just jump over it.
}
}
catch
{
//Here it will generate the custom exception you wanted and put it inside the errMsg
errMsg = new FileLoadException("File already compressed. Unzip the file and try again.").ToString();
Console.WriteLine(errMsg);
}
ofc this is made in console that is why I use the console.writeline you can just change those out

Is there a "nuclear option" for closing/freeing a file?

My original related question here (https://stackoverflow.com/questions/17332403/is-there-such-a-c-sharp-method-or-methodology-that-would-equate-to-filealready) was marked as a duplicate, and I used the supposed duplicate
(Is there a way to check if a file is in use?) to try to solve my problem, but I'm still getting flooded with Null Reference Exceptions on some file I/O operations.
Based on that halcyon post of yore, I altered the previous code from this:
public FileQuickRead(string filename)
{
try
{
SR = File.OpenText(filename);
}
catch (Exception ex)
{
CCR.ExceptionHandler(ex, "FileQuickRead.FileQuickRead");
}
. . .
...to this:
public FileQuickRead(string filename)
{
// Added 6/27/2013; adapted from https://stackoverflow.com/questions/876473/is-there-a-way-to-check-if-a-file-is-in-use
try
{
using (Stream stream = new FileStream(filename, FileMode.Open))
{
try
{
SR = File.OpenText(filename);
}
catch (Exception ex)
{
CCR.ExceptionHandler(ex, "FileQuickRead.FileQuickRead");
}
}
}
catch (Exception exc)
{
// If the "using Stream filename" fails
#if TRACE
UtilCE.LogInfo.Add2LogFile(string.Format("Catch block in FileQuickRead caught: {0}", exc.Message));
#endif
}
}
...The log file never contains the "Catch Block" string, so it's getting past the "using filename" but apparently failing on the call to File.OpenText().
Also, it's failing on the other two methods in the class, namely ReadLn and FileClose:
public string FileReadLn()
{
try
{
aLine = SR.ReadLine();
}
catch (Exception ex)
{
CCR.ExceptionHandler(ex, "FileQuickRead.FileReadLn");
}
return aLine;
}
public void FileClose()
{
try
{
SR.Close();
}
catch (Exception ex)
{
CCR.ExceptionHandler(ex, "FileQuickRead.FileClose");
}
}
I get a NullReferenceException on FileQuickRead, FileReadLn, then FileClose, three times in succession.
The only other thing in the class are these global declarations:
private StreamReader SR;
private string aLine;
Callers do so in this way:
fileQuickRead = new FileQuickRead(fn);
// Read the line from the file*
aLine = fileQuickRead.FileReadLn();
. . .
while ((aLine != null) && (aLine != ""))
. . .
aLine = fileQuickRead.FileReadLn();
if (aLine == null)
continue;
. . .
finally
{
fileQuickRead.FileClose();
}
Is the SR.Close() in the FileClose() method not enough? Do I need to do something to completely flush the file, or...???
Great - the only comment in the whole project, and it only divulges the achingly obvious.

what would happen when i try to continue the loop within the catch block

what would happen while searching the file through a string and could i try to continue the loop within the catch block against locked windows file in order to read next file.
TextReader rff = null;
try
{
rff = new StreamReader(fi.FullName);
String lne1 = rff.ReadToEnd();
if (lne1.IndexOf(txt) >= 0)
{
z = fi.FullName;
list22.Add(fi.FullName);
As long as the exception is caught by a try-catch nested inside the loop, you should be able to continue the loop no problem.
I'd say you'll have a try-catch around the statement where you are accessing the file within the loop. Then you can continue the loop after catching any exception.
While catching the exception try to catch only the most specific exception that may be thrown, so if you are looking to handle a locking situation you would look to catch the System.IO.IOException which is raised when files are used by other proccesses.
If you have to do some cleanup to do you should add a finally:
foreach (var fileName in fileNames)
{
var fi = new FileInfo(fileName);
StreamReader reader;
try
{
reader = new StreamReader(fi.FullName);
SomeMethodThatThrowsIOException();
}
catch (IOException ex)
{
continue;
}
finally
{
if (reader != null)
reader.Close();
}
}
or even better (since StreamReader implements IDisposable)
foreach (var fileName in fileNames)
{
try
{
var fi = new FileInfo(fileName);
using (var reader = new StreamReader(fi.FullName))
{
SomeMethodThatThrowsIOException();
}
}
catch (IOException ex) { }
}

c# How to access file if that file is processed by other process?

public static void WriteLine(string text)
{
StreamWriter log;
if (!File.Exists(Filename))
{
log = new StreamWriter(Filename);
}
else
{
log = File.AppendText(Filename);
}
while this method is processed, other process also call this method. There will be error occur "file has been acess by other process". How to solve this problem by waiting the previous process finish.
I think the op wants to wait until the filehandle is free to use and then write to the file. In this case you should try to get the filehandle, catch the exception and if the exception is because the file is accessed by another process then wait a short time and try again.
public static void WriteLine(string text)
{
bool success = false;
while (!success)
{
try
{
using (var fs = new FileStream(Filename, FileMode.Append))
{
// todo: write to stream here
success = true;
}
}
catch (IOException)
{
int errno = Marshal.GetLastWin32Error();
if(errno != 32) // ERROR_SHARING_VIOLATION
{
// we only want to handle the
// "The process cannot access the file because it is being used by another process"
// exception and try again, all other exceptions should not be caught here
throw;
}
Thread.Sleep(100);
}
}
}
Both processes need to create a FileStream where they specify a FileShare mode of Write. You can then also drop the test whether the file exists, and just use the Append FileMode.

C# try-catch-else

One thing that has bugged me with exception handling coming from Python to C# is that in C# there doesn't appear to be any way of specifying an else clause. For example, in Python I could write something like this (Note, this is just an example. I'm not asking what is the best way to read a file):
try
{
reader = new StreamReader(path);
}
catch (Exception)
{
// Uh oh something went wrong with opening the file for reading
}
else
{
string line = reader.ReadLine();
char character = line[30];
}
From what I have seen in most C# code people would just write the following:
try
{
reader = new StreamReader(path);
string line = reader.ReadLine();
char character = line[30];
}
catch (Exception)
{
// Uh oh something went wrong, but where?
}
The trouble with this is that I don't want to catch out of range exception coming from the fact that the first line in the file may not contain more than 30 characters. I only want to catch exceptions relating to the reading of the file stream. Is there any similar construct I can use in C# to achieve the same thing?
Catch a specific class of exceptions
try
{
reader = new StreamReader(path);
string line = reader.ReadLine();
char character = line[30];
}
catch (IOException ex)
{
// Uh oh something went wrong with I/O
}
catch (Exception ex)
{
// Uh oh something else went wrong
throw; // unless you're very sure what you're doing here.
}
The second catch is optional, of course. And since you don't know what happened, swallowing this most general exception is very dangerous.
You could write it like:
bool success = false;
try {
reader = new StreamReader(path);
success = true;
}
catch(Exception) {
// Uh oh something went wrong with opening the file for reading
}
finally {
if(success) {
string line = reader.ReadLine();
char character = line[30];
}
}
You can do this:
try
{
reader = new StreamReader(path);
}
catch (Exception)
{
// Uh oh something went wrong with opening the file for reading
}
string line = reader.ReadLine();
char character = line[30];
But of course, you will have to set reader into a correct state or return out of the method.
Catch more specific exceptions.
try {
reader = new StreamReader(path);
string line = reader.ReadLine();
char character = line[30];
}
catch(FileNotFoundException e) {
// thrown by StreamReader constructor
}
catch(DirectoryNotFoundException e) {
// thrown by StreamReader constructor
}
catch(IOException e) {
// some other fatal IO error occured
}
Further, in general, handle the most specific exception possible and avoid handling the base System.Exception.
You can nest your try statements, too
Exceptions are used differently in .NET; they are for exceptional conditions only.
In fact, you should not catch an exception unless you know what it means, and can actually do something about it.
You can have multiple catch clauses, each specific to the type of exception you wish to catch. So, if you only want to catch IOExceptions, then you could change your catch clause to this:
try
{
reader = new StreamReader(path);
string line = reader.ReadLine();
char character = line[30];
}
catch (IOException)
{
}
Anything other than an IOException would then propagate up the call stack. If you want to also handle other exceptions, then you can add multiple exception clauses, but you must ensure they are added in most specific to most generic order. For example:
try
{
reader = new StreamReader(path);
string line = reader.ReadLine();
char character = line[30];
}
catch (IOException)
{
}
catch (Exception)
{
}
More idiomatically, you would employ the using statement to separate the file-open operation from the work done on the data it contains (and include automatic clean-up on exit)
try {
using (reader = new StreamReader(path))
{
DoSomethingWith(reader);
}
}
catch(IOException ex)
{
// Log ex here
}
It is also best to avoid catching every possible exception -- like the ones telling you that the runtime is about to expire.
Is there any similar construct I can use in C#
to acheive the same thing?
No.
Wrap your index accessor with an "if" statement which is the best solution in your case in case of performance and readability.
if (line.length > 30) {
char character = line [30];
}
After seeing the other suggested solutions, here is my approach:
try {
reader = new StreamReader(path);
}
catch(Exception ex) {
// Uh oh something went wrong with opening the file stream
MyOpeningFileStreamException newEx = new MyOpeningFileStreamException();
newEx.InnerException = ex;
throw(newEx);
}
string line = reader.ReadLine();
char character = line[30];
Of course, doing this makes sense only if you are interested in any exceptions thrown by opening the file stream (as an example here) apart from all other exceptions in the application. At some higher level of the application, you then get to handle your MyOpeningFileStreamException as you see fit.
Because of unchecked exceptions, you can never be 100% certain that catching only IOException out of the entire code block will be enough -- the StreamReader can decide to throw some other type of exception too, now or in the future.
You can do something similar like this:
bool passed = true;
try
{
reader = new StreamReader(path);
}
catch (Exception)
{
passed = false;
}
if (passed)
{
// code that executes if the try catch block didnt catch any exception
}
I have taken the liberty to transform your code a bit to demonstrate a few important points.
The using construct is used to open the file. If an exception is thrown you will have to remember to close the file even if you don't catch the exception. This can be done using a try { } catch () { } finally { } construct, but the using directive is much better for this. It guarantees that when the scope of the using block ends the variable created inside will be disposed. For a file it means it will be closed.
By studying the documentation for the StreamReader constructor and ReadLine method you can see which exceptions you may expect to be thrown. You can then catch those you finde appropriate. Note that the documented list of exceptions not always is complete.
// May throw FileNotFoundException, DirectoryNotFoundException,
// IOException and more.
try {
using (StreamReader streamReader = new StreamReader(path)) {
try {
String line;
// May throw IOException.
while ((line = streamReader.ReadLine()) != null) {
// May throw IndexOutOfRangeException.
Char c = line[30];
Console.WriteLine(c);
}
}
catch (IOException ex) {
Console.WriteLine("Error reading file: " + ex.Message);
}
}
}
catch (FileNotFoundException ex) {
Console.WriteLine("File does not exists: " + ex.Message);
}
catch (DirectoryNotFoundException ex) {
Console.WriteLine("Invalid path: " + ex.Message);
}
catch (IOException ex) {
Console.WriteLine("Error reading file: " + ex.Message);
}
Sounds like you want to do the second thing only if the first thing succeeded. And maybe catching different classes of exception is not appropriate, for example if both statements could throw the same class of exception.
try
{
reader1 = new StreamReader(path1);
// if we got this far, path 1 succeded, so try path2
try
{
reader2 = new StreamReader(path2);
}
catch (OIException ex)
{
// Uh oh something went wrong with opening the file2 for reading
// Nevertheless, have a look at file1. Its fine!
}
}
catch (OIException ex)
{
// Uh oh something went wrong with opening the file1 for reading.
// So I didn't even try to open file2
}
There might not be any native support for try { ... } catch { ... } else { ... } in C#, but if you are willing to shoulder the overhead of using a workaround, then the example shown below might be appealing:
using System;
public class Test
{
public static void Main()
{
Example("ksEE5A.exe");
}
public static char Example(string path) {
var reader = default(System.IO.StreamReader);
var line = default(string);
var character = default(char);
TryElse(
delegate {
Console.WriteLine("Trying to open StreamReader ...");
reader = new System.IO.StreamReader(path);
},
delegate {
Console.WriteLine("Success!");
line = reader.ReadLine();
character = line[30];
},
null,
new Case(typeof(NullReferenceException), error => {
Console.WriteLine("Something was null and should not have been.");
Console.WriteLine("The line variable could not cause this error.");
}),
new Case(typeof(System.IO.FileNotFoundException), error => {
Console.WriteLine("File could not be found:");
Console.WriteLine(path);
}),
new Case(typeof(Exception), error => {
Console.WriteLine("There was an error:");
Console.WriteLine(error);
}));
return character;
}
public static void TryElse(Action pyTry, Action pyElse, Action pyFinally, params Case[] pyExcept) {
if (pyElse != null && pyExcept.Length < 1) {
throw new ArgumentException(#"there must be exception handlers if else is specified", nameof(pyExcept));
}
var doElse = false;
var savedError = default(Exception);
try {
try {
pyTry();
doElse = true;
} catch (Exception error) {
savedError = error;
foreach (var handler in pyExcept) {
if (handler.IsMatch(error)) {
handler.Process(error);
savedError = null;
break;
}
}
}
if (doElse) {
pyElse();
}
} catch (Exception error) {
savedError = error;
}
pyFinally?.Invoke();
if (savedError != null) {
throw savedError;
}
}
}
public class Case {
private Type ExceptionType { get; }
public Action<Exception> Process { get; }
private Func<Exception, bool> When { get; }
public Case(Type exceptionType, Action<Exception> handler, Func<Exception, bool> when = null) {
if (!typeof(Exception).IsAssignableFrom(exceptionType)) {
throw new ArgumentException(#"exceptionType must be a type of exception", nameof(exceptionType));
}
this.ExceptionType = exceptionType;
this.Process = handler;
this.When = when;
}
public bool IsMatch(Exception error) {
return this.ExceptionType.IsInstanceOfType(error) && (this.When?.Invoke(error) ?? true);
}
}
If you happen to be in a loop, then you can put a continue statement in the catch blocks. This will cause the remaining code of that block to be skipped.
If you are not in a loop, then there is no need to catch the exception at this level. Let it propagate up the call stack to a catch block that knows what to do with it. You do this by eliminating the entire try/catch framework at the current level.
I like try/except/else in Python too, and maybe they will get added to C# some day (just like multiple return values were). But if you think about exceptions a little differently, else blocks are not strictly necessary.

Categories