List<string> errorLog = new List<string>();
foreach (DirectoryInfo dir in directories)
{
try
{
dir.Delete(true);
}
catch (System.IO.IOException msg)
{
code = 5;
errorLog.Add(String.Concat(dir.FullName, " ", msg.Message));
Console.WriteLine("Error Removing the directory: {0}", dir.FullName);
}
}
I have a for each loop that will go through a list of directories and remove them, but keep the parent directory. Should an error occur, I would like to log it. I created a list and in the catch add the errors. At the end, I can check the length of errorLog list and if it's more than zero, I can print them. I've seen posts where they call using and streamwriter within the catch, but what happens if something were to occur while writing the error log?
Is what I'm doing considered bad practice? If so, what should I do ?
I think you've got the right idea. There are many solutions, but recently I tried rerouting the console output to file and it worked pretty well. Regarding your solution, it would look like:
try
{
FileStream oStream;
StreamWriter sWriter;
var oldOut = Console.Out;
var desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
const string outputFileName = "\\errorlog.txt";
var fullPath = string.Concat(desktopPath, outputFileName);
Console.SetOut(sWriter);
foreach (DirectoryInfo dir in directories)
{
try
{
dir.Delete(true);
}
catch(System.IO.IOException msg)
{
code = 5;
errorLog.Add(String.Concat(dir.FullName," ",msg.Message));
Console.WriteLine("Error Removing the directory: {0}", dir.FullName);
}
}
}
catch(Exception e)
{
//handle error with streams or file
}
finally
{
//ensures that we close the connections and such
Console.SetOut(oldOut);
sWriter.Close();
oStream.Close();
}
The finally block ensures that if any unhandled thing happens, the stream and file will still be closed.
Related
I'm working in C# and I try to do a program that get some infoes the files in a Directory. I made it but i have a problem with the error Handling. When the program runs and for example I give just random numbers to list file infoes i get this error message:
"System.IO.DirectoryNotFoundException: "'Could not find a part of the path 'C:\Temp\first_project\first_project\bin\Debug\12345'.'"
Please someone help me to do the error handling.
Thank you in advance.
using System;
using System.IO;
class Test
{
static void Main(string[] args)
{
Console.WriteLine("Please :");
string hely = Console.ReadLine();
string[] __file = Directory.GetFiles(hely);
string[] __dir = Directory.GetDirectories(hely);
foreach (string i in __file)
{
FileInfo fajl = new FileInfo(i);
Console.WriteLine("{0},{1},{2}", fajl.Name, fajl.Extension, fajl.LastWriteTime.ToString());
}
foreach (string i in __dir)
{
DirectoryInfo _file = new DirectoryInfo(i);
Console.WriteLine("{0},{1},{2}", _file.Name, _file.Extension, _file.LastWriteTime.ToString());
}
Console.ReadKey();
}
}
You should check existence of a path with
System.IO.Directory.Exists(directory)
and of a file with
System.IO.File.Exists(filePath)
Then, you need to take the try-catch block inside the for-loop, to catch any possible exceptions that occur because of insufficient rights/permissions.
e.g.
foreach (string i in __file)
{
try
{
FileInfo fajl = new FileInfo(i);
Console.WriteLine("{0},{1},{2}", fajl.Name, fajl.Extension, fajl.LastWriteTime.ToString());
}
catch (System.Exception ex)
{
System.Console.WriteLine(ex.Message);
throw;
}
}
You could also create two try-catch blocks - depends on what you want to do.
try
{
foreach (string i in __file)
{
try
{
FileInfo fajl = new FileInfo(i);
Console.WriteLine("{0},{1},{2}", fajl.Name, fajl.Extension, fajl.LastWriteTime.ToString());
}
catch (System.Exception ex)
{
System.Console.WriteLine(ex.Message);
throw;
}
}
}
catch (System.Exception exLoop)
{
System.Console.WriteLine(exLoop.Message);
throw;
}
Note that in your example, you should first check if the directory "hely" exists:
if (!System.IO.Directory.Exists(hely))
{
System.Console.Error.WriteLine("Directory \"{0}\" does not exist.", hely);
System.Environment.Exit(1);
// or: return;
}
Since exception handling is usually very slow, I would however recommend that you check for the existence of the file/directory explicitly. It would also be a good idea to do so for the file/directory-listing & read-access rights for the respective user. But even if you do so, keep the try-catch, because there might be cases where your program suddenly fails - e.g. when a removable storage is forcefully removed.
Use try catch
using System;
using System.IO;
class Test
{
static void Main(string[] args)
{
Console.WriteLine("Please :");
string hely = Console.ReadLine();
try
{
string[] __file = Directory.GetFiles(hely);
string[] __dir = Directory.GetDirectories(hely);
foreach (string i in __file)
{
FileInfo fajl = new FileInfo(i);
Console.WriteLine("{0},{1},{2}", fajl.Name, fajl.Extension, fajl.LastWriteTime.ToString());
}
foreach (string i in __dir)
{
DirectoryInfo _file = new DirectoryInfo(i);
Console.WriteLine("{0},{1},{2}", _file.Name, _file.Extension, _file.LastWriteTime.ToString());
}
}
catch(System.IO.DirectoryNotFoundException ex)
{
Console.WriteLine("Directory not found");
}
Console.ReadKey();
}
}
You can check if the file exists
foreach (string i in __file)
{
if (File.Exists(i))
{
FileInfo fajl = new FileInfo(i);
Console.WriteLine("{0},{1},{2}", fajl.Name, fajl.Extension, fajl.LastWriteTime.ToString());
}
}
RTFM?
Read Directory.GetFiles method
It says that you will get the DirectoryNotfound exception if the specified path is not found. Obviously folder 'C:\Temp\first_project\first_project\bin\Debug\12345' does not exist.
Proper code would be:
string hely = ...
try
{
string[] files = Directory.GetFiles(hely);
ProcessFiles(files);
}
catch (DirectoryNotFoundException exc)
{
Console.WriteLine(exc.Message);
}
If you don't know how to react on exceptions read MSDN about exception handling
I am wondering on how to create a new directory for a log event file in windows service through c#
I have the following code:
public static void WriteLog(string Message)
{
StreamWriter sw = null;
try
{
sw = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "\\DataFile.txt", true);
//sw = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "C:\\MulpuriServiceLOG\\data.txt", true);
//sw.WriteLine(DateTime.Now.ToString() + ": " + Message);
sw.WriteLine(Message);
sw.Flush();
sw.Close();
}
catch{}
}
As the docuemtation states for the Directory.CreateDirectory(path):
Creates all directories and subdirectories in the specified path unless they already exist.
Modified from the example source code:
string path = #"c:\MyDir";
try
{
// Try to create the directory.
Directory.CreateDirectory(path);
}
catch (Exception e)
{
Console.WriteLine("The process failed: {0}", e.ToString());
}
finally {}
There is a really great tutorial on dotnetperls containing example code, exceptions, tips and other useful information about creating directories!
Look up that SO-question to create folders inside the same directory your executable has started, or simple use relative paths instead of absolute ones:
Directory.CreateDirectory("Test");
That way you will never have conflicts about finding the correct path!
File yourFolder= new File("C:/yourFolder");
// if the directory does not exist, create it
if (!yourFolder.exists()) {
System.out.println("Creando directorio: " + yourFolder.getName());
boolean result = false;
try
{
yourFolder.mkdir();
result = true;
}
catch(SecurityException se){
}
if(result) {
System.out.println("Folder created");
}
}
I have the following C# code for calculating each file's hash in a certain, user specified directory. The point is that it works fine, until it encounters a file that it cannot access. When it finds something like this, it just throws an error message and exits the program. What I want it instead to do is, throw an error message with the name of the file that cannot be accessed, write that there is an error in accessing that file, and continue executing the program with the other files in the directory. If someone can help me edit my code and achieve those things I would be glad.
private void SHA256Directory(string directory)
{
try
{
SHA256 DirectorySHA256 = SHA256Managed.Create();
byte[] hashValue;
DirectoryInfo dir = new DirectoryInfo(directory);
FileInfo[] files = dir.GetFiles();
foreach (FileInfo fInfo in files)
{
FileStream fStream = fInfo.Open(FileMode.Open);
fStream.Position = 0;
hashValue = DirectorySHA256.ComputeHash(fStream);
Console.WriteLine(fInfo.Name);
Miscellaneous.ByteArrayToHex(hashValue);
Miscellaneous.ByteArrayToBase64(hashValue);
Console.WriteLine();
fStream.Close();
}
return;
}
catch(DirectoryNotFoundException)
{
Console.WriteLine("Error: The directory specified could not be found.");
}
catch(IOException)
{
Console.WriteLine("Error: A file in the directory could not be accessed.");
}
catch(ArgumentNullException)
{
Console.WriteLine("Error: The argument cannot be null or empty.");
}
}
Move your try/catch inside the foreach. You haven't explained in your post, but I'm guessing that's where you encounter the exception.
In doing so, any exception caused by the code in there will be caught and allow the loop to continue.
Careful, though -- these two lines are still not exception-safe:
DirectoryInfo dir = new DirectoryInfo(directory);
FileInfo[] files = dir.GetFiles();
You'll want to account for that as well.
If you want it to show what exactly what file/directory caused the issue, just toString the exception, for example:
catch(DirectoryNotFoundException ex)
{
Console.WriteLine("Error: The directory specified could not be found: " + ex.toString());
}
If toString doesn't give you the desired output, try ex.Message. I always just use toString though.
EDIT credit to Ken Henderson
When using any kind of Stream, you should put it in a using block. The garbage collector will Close the stream eventually, but its good practice to do this, as a using block will close the stream as soon as you're done using it:
using (FileStream fStream = fInfo.Open(FileMode.Open))
{
fStream.Position = 0;
hashValue = DirectorySHA256.ComputeHash(fStream);
Console.WriteLine(fInfo.Name);
Miscellaneous.ByteArrayToHex(hashValue);
Miscellaneous.ByteArrayToBase64(hashValue);
Console.WriteLine();
} // No need for fStream.Close() any more, the using block will take care of it for you
You should reorganize your code like this:
private void SHA256Directory(string directory)
{
try
{
DirectoryInfo dir = new DirectoryInfo(directory);
FileInfo[] files = dir.GetFiles();
foreach (FileInfo fInfo in files)
{
try
{
SHA256 DirectorySHA256 = SHA256Managed.Create();
byte[] hashValue;
FileStream fStream = fInfo.Open(FileMode.Open);
fStream.Position = 0;
hashValue = DirectorySHA256.ComputeHash(fStream);
Console.WriteLine(fInfo.Name);
Miscellaneous.ByteArrayToHex(hashValue);
Miscellaneous.ByteArrayToBase64(hashValue);
Console.WriteLine();
fStream.Close();
}
catch (...)
{
// Handle other exceptions here. Through finfo, you can
// access the file name
}
}
}
catch (...)
{
// Handle directory/file iteration exceptions here
}
}
Scope is the keyword here.
Your try catch surrounds the entire foreach. This means that when there is an error, it will exit out of the foreach. You want to have the try-catch closer to the point of origin (that being fInfo.Open(FileMode.Open)). That way, after an error it can just continue processing the loop.
Try this instead:
private void SHA256Directory(string directory)
{
SHA256 DirectorySHA256 = SHA256Managed.Create();
byte[] hashValue;
DirectoryInfo dir = new DirectoryInfo(directory);
FileInfo[] files = dir.GetFiles();
foreach (FileInfo fInfo in files)
{
try
{
FileStream fStream = fInfo.Open(FileMode.Open);
fStream.Position = 0;
hashValue = DirectorySHA256.ComputeHash(fStream);
Console.WriteLine(fInfo.Name);
Miscellaneous.ByteArrayToHex(hashValue);
Miscellaneous.ByteArrayToBase64(hashValue);
Console.WriteLine();
fStream.Close();
}
catch(DirectoryNotFoundException)
{
Console.WriteLine("Error: The directory specified could not be found.");
}
catch(IOException)
{
Console.WriteLine("Error: A file in the directory could not be accessed.");
}
catch(ArgumentNullException)
{
Console.WriteLine("Error: The argument cannot be null or empty.");
}
}
return;
}
}
You should also handle the UnauthorizedAccessException which is thrown if file is not accessible.
Might be I'm overseeing something, because the solution is rather simple, but;
place the Try-Catch block dealing with the access problems inside the for each - in case one file is not accessible, the exception is thrown, catched and after printing the error message the foreach is continued with the next file in the list.
private void SHA256Directory(string directory)
{
try
{
SHA256 DirectorySHA256 = SHA256Managed.Create();
byte[] hashValue;
DirectoryInfo dir = new DirectoryInfo(directory);
FileInfo[] files = dir.GetFiles();
foreach (FileInfo fInfo in files)
{
try
{
FileStream fStream = fInfo.Open(FileMode.Open);
fStream.Position = 0;
hashValue = DirectorySHA256.ComputeHash(fStream);
Console.WriteLine(fInfo.Name);
Miscellaneous.ByteArrayToHex(hashValue);
Miscellaneous.ByteArrayToBase64(hashValue);
Console.WriteLine();
fStream.Close();
}
catch(IOException)
{
Console.WriteLine("Error: A file in the directory could not be accessed.");
}
}
return;
}
catch(DirectoryNotFoundException)
{
Console.WriteLine("Error: The directory specified could not be found.");
}
catch(ArgumentNullException)
{
Console.WriteLine("Error: The argument cannot be null or empty.");
}
}
To know which file is not accessible you could use the following snippet :
catch(FileNotFoundException ex)
{
Console.writeLine("File not found " + ex.FileName);
}
handle UnauthorizedAccessException and put try statement in foreach statement.
private void SHA256Directory(string directory)
{
SHA256 DirectorySHA256 = SHA256Managed.Create();
byte[] hashValue;
DirectoryInfo dir = new DirectoryInfo(directory);
FileInfo[] files = dir.GetFiles();
foreach (FileInfo fInfo in files)
{
try
{
FileStream fStream = fInfo.Open(FileMode.Open);
fStream.Position = 0;
hashValue = DirectorySHA256.ComputeHash(fStream);
Console.WriteLine(fInfo.Name);
Miscellaneous.ByteArrayToHex(hashValue);
Miscellaneous.ByteArrayToBase64(hashValue);
Console.WriteLine();
fStream.Close();
}
catch (DirectoryNotFoundException)
{
Console.WriteLine("Error: The directory specified could not be found.");
}
catch (UnauthorizedAccessException)
{
Console.WriteLine("Error: A file in the directory could not be accessed.in {0}", fInfo.Name);
}
catch (ArgumentNullException)
{
Console.WriteLine("Error: The argument cannot be null or empty.");
}
catch (IOException)
{
Console.WriteLine("Error:IOExcepiton occured");
}
}
return;
}
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;
}
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) { }
}