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
Related
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 6 years ago.
Improve this question
I apologize if this sounds like a ignorant question but I am quite new to C#. I am one error away from getting my program to work:
"the name 'filesInfo' does not exist in the current context"
I am trying to get this variable to exist and attempted at solving this by declaring it outside the foreach loop, but to no avail.
Here is my current script:
public class MyClass
{
public static string src = #"C:\Users\Bold Defiance\Desktop\FolderA";
public static string dst = #"C:\Users\Bold Defiance\Desktop\FolderB";
public static string[] files = System.IO.Directory.GetFiles(src, "*.txt");
public void Move_Modified_Files()
{
foreach (string s in files)
{
string fileName = Path.GetFileName(s);
FileInfo filesInfo = new FileInfo(fileName);
}
try
{
if (filesInfo.LastWriteTime.Date == DateTime.Today.Date)
{
File.Move(src, dst);
Console.WriteLine("Modified files in {0} were moved to {1}", src, dst);
}
else
{
Console.WriteLine("No new or modified files were created today.");
}
}
catch (Exception e)
{
Console.WriteLine("The process failed: {0}", e.ToString());
}
}
}
class Program
{
static void Main(string[] args)
{
MyClass cls = new MyClass();
cls.Move_Modified_Files();
}
}
You are declaring filesInfo within the foreach loop. As such, its scope is restricted to that loop. If you want to use it elsewhere, you have to move it to the corresponding scope:
FileInfo filesInfo;
foreach (string s in files)
{
string fileName = Path.GetFileName(s);
filesInfo = new FileInfo(fileName);
}
try
{
if (filesInfo.LastWriteTime.Date == DateTime.Today.Date)
{
File.Move(src, dst);
Console.WriteLine("Modified files in {0} were moved to {1}", src, dst);
}
else
{
Console.WriteLine("No new or modified files were created today.");
}
}
catch (Exception e)
{
Console.WriteLine("The process failed: {0}", e.ToString());
}
That being said, you are currently overriding filesInfo on every iteration of the loop. I imagine that you wanted to check filesInfo for every value of s, so what you actually wanted to do is this:
foreach (string s in files)
{
string fileName = Path.GetFileName(s);
FileInfo filesInfo = new FileInfo(fileName);
try
{
if (filesInfo.LastWriteTime.Date == DateTime.Today.Date)
{
File.Move(src, dst);
Console.WriteLine("Modified files in {0} were moved to {1}", src, dst);
}
else
{
Console.WriteLine("No new or modified files were created today.");
}
}
catch (Exception e)
{
Console.WriteLine("The process failed: {0}", e.ToString());
}
}
Try this:
public void Move_Modified_Files()
{
foreach (string s in files)
{
string fileName = Path.GetFileName(s);
FileInfo filesInfo = new FileInfo(fileName);
try
{
if (filesInfo.LastWriteTime.Date == DateTime.Today.Date)
{
File.Move(src, dst);
Console.WriteLine("Modified files in {0} were moved to {1}", src, dst);
}
else
{
Console.WriteLine("No new or modified files were created today.");
}
}
catch (Exception e)
{
Console.WriteLine("The process failed: {0}", e.ToString());
}
}
}
You declared
FileInfo filesInfo = new FileInfo(fileName);
inside the first loop. When this context ends with the } the variable will disappear.
My guess is that you wanted to do this.
public class MyClass
{
public static string src = #"C:\Users\Bold Defiance\Desktop\FolderA";
public static string dst = #"C:\Users\Bold Defiance\Desktop\FolderB";
public static string[] files = System.IO.Directory.GetFiles(src, "*.txt");
public void Move_Modified_Files()
{
foreach (string s in files)
{
// These values will exist until their enclosing context is closed
// The context starts with the most recent opening bracket {
// So these values, will exist until this loop iterates to the next value
string fileName = Path.GetFileName(s);
FileInfo filesInfo = new FileInfo(fileName);
// Attempt to use the currently selected fileinfo
try
{
if (filesInfo.LastWriteTime.Date == DateTime.Today.Date)
{
File.Move(src, dst);
Console.WriteLine("Modified files in {0} were moved to {1}", src, dst);
}
else
{
Console.WriteLine("No new or modified files were created today.");
}
}
catch (Exception e)
{
Console.WriteLine("The process failed: {0}", e.ToString());
}
// The next } bracket below is the one that closes the context mentioned earlier
// When it closes, all values declared in this sub-context will no longer exist.
}
}
}
class Program
{
static void Main(string[] args)
{
MyClass cls = new MyClass();
cls.Move_Modified_Files();
}
}
I need to save in database file Name and Size in byte from folder and all subfolder.
In this folder lay 1 000 000 files.
And when I use example from msdn it works 4 days, that very slowly.
static void Main(string[] args)
{
string pdxPathDocFiles = System.Configuration.ConfigurationManager.AppSettings["PDX_PathDocFiles"] as string;
if (string.IsNullOrEmpty(pdxPathDocFiles))
{
Console.WriteLine("In the configuration file is missing the path to the root directory - PDX_PathDocFiles.");
}
else
{
if (!Directory.Exists(pdxPathDocFiles))
{
Console.WriteLine("Directory not found");
}
else
{
try
{
Console.WriteLine("rootPath: " + pdxPathDocFiles);
PayDox_EPD19_T20_RGMEntities db = new PayDox_EPD19_T20_RGMEntities();
System.IO.DirectoryInfo rootDir = new DirectoryInfo(pdxPathDocFiles);
db.FileDBRecord.RemoveRange(db.FileDBRecord);
WalkDirectoryTree(rootDir, rootDir.ToString(), db);
db.SaveChanges();
}
catch (Exception)
{
Console.WriteLine("Failed to connect to the database");
}
Console.WriteLine("All ok");
}
}
Console.WriteLine("Bye, Good Day.");
}
static void WalkDirectoryTree(System.IO.DirectoryInfo root, string rootDir, PayDox_EPD19_T20_RGMEntities db)
{
System.IO.FileInfo[] files = null;
System.IO.DirectoryInfo[] subDirs = null;
try
{
files = root.GetFiles("*.*");
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine(e.Message);
}
catch (System.IO.DirectoryNotFoundException e)
{
Console.WriteLine(e.Message);
}
if (files != null)
{
foreach (System.IO.FileInfo fi in files)
{
db.FileDBRecord.Add(new FileDBRecord { FileName = fi.FullName.Replace(rootDir, ""), FileSize = fi.Length });
}
subDirs = root.GetDirectories();
foreach (System.IO.DirectoryInfo dirInfo in subDirs)
{
WalkDirectoryTree(dirInfo, rootDir, db);
}
}
db.SaveChanges();
}
When I try another way, it throw-out with exception stack overflow exception.
static void Main(string[] args)
{
string pdxPathDocFiles = System.Configuration.ConfigurationManager.AppSettings["PDX_PathDocFiles"] as string;
if (string.IsNullOrEmpty(pdxPathDocFiles))
{
Console.WriteLine("In the configuration file is missing the path to the root directory - PDX_PathDocFiles.");
}
else
{
if (!Directory.Exists(pdxPathDocFiles))
{
Console.WriteLine("Directory not found");
}
else
{
try
{
Console.WriteLine("rootPath: " + pdxPathDocFiles);
PayDox_EPD19_T20_RGMEntities db = new PayDox_EPD19_T20_RGMEntities();
db.FileDBRecord.RemoveRange(db.FileDBRecord);
db.SaveChanges();
Console.WriteLine("Remove data from table");
System.IO.FileInfo[] files = null;
System.IO.DirectoryInfo rootDir2 = new DirectoryInfo(pdxPathDocFiles);
try
{
files = rootDir2.GetFiles("*.*", SearchOption.AllDirectories);
Console.WriteLine("Reed {0} fileName", files.Length);
}
catch (UnauthorizedAccessException ex)
{
Console.WriteLine("You do not have permission to access one or more folders in this directory tree.");
Console.WriteLine(ex.Message);
return;
}
db.FileDBRecord.AddRange(files.Select(x => new FileDBRecord { FileName = x.FullName.Replace(pdxPathDocFiles, ""), FileSize = x.Length }));
db.SaveChanges();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.WriteLine("All ok");
}
}
Console.WriteLine("Bye, Good Day.");
}
How make program faster, maybe add multithreading?
For starters, your code isn't async. Break this out into a separate class and make the methods async. This allows the thread to be used while waiting for an IO operation. Anytime your calling the Database or File system use async equivalent methods.
The second thing I would do is try to make is so each transaction is atomic. If you doing something x amount of times, write the program in such a way that each x time can be done is isolation. Once that is done you can run these is parallel by creating a new Task (Task.Run).
Once those 2 are done and the task is still taking a while, look into TPL Dataflow. That can buffer requests for you to optimize your process.
I improved first example from msdn, by adding there TPL library.
Now it working 4 hour, not 4 days.
static void Main(string[] args)
{
string pdxPathDocFiles = System.Configuration.ConfigurationManager.AppSettings["PDX_PathDocFiles"] as string;
if (string.IsNullOrEmpty(pdxPathDocFiles))
{
Console.WriteLine("In the configuration file is missing the path to the root directory - PDX_PathDocFiles.");
}
else
{
if (!Directory.Exists(pdxPathDocFiles))
{
Console.WriteLine("Directory not found");
}
else
{
try
{
Console.WriteLine("rootPath: " + pdxPathDocFiles);
PayDox_EPD19_T20_RGMEntities db = new PayDox_EPD19_T20_RGMEntities();
System.IO.DirectoryInfo rootDir = new DirectoryInfo(pdxPathDocFiles);
db.Database.ExecuteSqlCommand("TRUNCATE TABLE [FileDBRecord]");
db.SaveChanges();
db.Dispose();
Console.WriteLine("Remove data from table");
WalkDirectoryTree(rootDir, rootDir.ToString());
Console.WriteLine("All ok");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
Console.WriteLine("Bye, Good Day.");
Console.WriteLine("Processing complete. Press any key to exit.");
Console.ReadKey();
}
static void WalkDirectoryTree(System.IO.DirectoryInfo root, string rootDir)
{
//Console.WriteLine("Go to folder: "+ root.FullName.Replace(rootDir, ""));
System.IO.FileInfo[] files = null;
System.IO.DirectoryInfo[] subDirs = null;
try
{
files = root.GetFiles("*.*");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
if (files != null)
{
PayDox_EPD19_T20_RGMEntities db = new PayDox_EPD19_T20_RGMEntities();
foreach (var currentElement in files)
{
db.FileDBRecord.Add(new FileDBRecord { FileName = currentElement.FullName.Replace(rootDir, ""), FileSize = currentElement.Length });
}
db.SaveChanges();
db.Dispose();
subDirs = root.GetDirectories();
Parallel.ForEach(subDirs,
currentElement =>
{
try
{
WalkDirectoryTree(currentElement, rootDir);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
});
}
}
}
maybe we can fix your second code.. (untested, but may not throw the exception)
if you test it, let me know if it is faster..
static void Main(string[] args)
{
string pdxPathDocFiles = System.Configuration.ConfigurationManager.AppSettings["PDX_PathDocFiles"] as string;
if (string.IsNullOrEmpty(pdxPathDocFiles))
{
Console.WriteLine("In the configuration file is missing the path to the root directory - PDX_PathDocFiles.");
}
else
{
if (!Directory.Exists(pdxPathDocFiles))
{
Console.WriteLine("Directory not found");
}
else
{
try
{
Console.WriteLine("rootPath: " + pdxPathDocFiles);
PayDox_EPD19_T20_RGMEntities db = new PayDox_EPD19_T20_RGMEntities();
db.FileDBRecord.RemoveRange(db.FileDBRecord);
db.SaveChanges();
Console.WriteLine("Remove data from table");
IList<FileDBRecord> files = null;
System.IO.DirectoryInfo rootDir2 = new DirectoryInfo(pdxPathDocFiles);
try
{
files = rootDir2.GetFiles("*.*", SearchOption.AllDirectories).Select(x => new FileDBRecord { FileName = x.FullName.Replace(pdxPathDocFiles, ""), FileSize = x.Length });
Console.WriteLine("Reed {0} fileName", files.Length);
}
catch (UnauthorizedAccessException ex)
{
Console.WriteLine("You do not have permission to access one or more folders in this directory tree.");
Console.WriteLine(ex.Message);
return;
}
files.Foreach(db.FileDBRecord);
db.SaveChanges();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.WriteLine("All ok");
}
}
Console.WriteLine("Bye, Good Day.");
}
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.
I have this code in C# that works fine in some users.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Threading;
namespace Rename_OST
{
class Program
{
static public void killOutlook()
{
try
{
string process = "OUTLOOK";
foreach (Process outLook in Process.GetProcessesByName(process))
{
outLook.Kill();
}
}
catch (Exception) { }
}
static public void startOutlook()
{
try
{
//busca el path del Outlook
Process.Start("OUTLOOK");
}
catch (Exception)
{
Console.WriteLine("Could'n open Outlook. Please start Outlook and press any key.");
Console.ReadKey();
}
}
static public void replaceOutlook()
{
string ostPath = "C:\\Users\\" + Environment.UserName + "\\AppData\\Local\\Microsoft\\Outlook\\";
string ostFile = "Outlook.ost";
string ostNewFile = "Outlook.ost.txt";
try
{
if (!File.Exists(ostPath + ostNewFile))
{
File.Move(ostPath + ostFile, ostPath + ostNewFile);
}
else
{
File.Delete(ostPath + ostNewFile);
File.Move(ostPath + ostFile, ostPath + ostNewFile);
}
}
catch (FileNotFoundException)
{
Console.WriteLine("The OST file was not found.");
Console.ReadKey();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadKey();
}
}
static void Main(string[] args)
{
Console.WriteLine("Closing Outlook client...");
killOutlook();
Console.WriteLine("Replacing OST file name...");
Thread.Sleep(5000);
replaceOutlook();
Thread.Sleep(5000);
Console.WriteLine("Starting Outlook client...");
startOutlook();
}
}
}
The code only works if the file is named outlook.ost. How can I change the code in order that rename the OST file search regardless of the name.
Thanks in advance
Iterate through the files in the directory to check if they're .OST and then rename them.
// GET ALL FILES IN DIRECTORY
string[] fileEntries = Directory.GetFiles(ostPath);
// CHECK EACH FILE
foreach (string fileName in fileEntries)
{
// IS IT AN OST?
if (Path.GetExtension(fileName).ToLower() == ".ost")
{
// RENAME LOGIC HERE, EXAMPLE:
File.Move(fileName, fileName + ".OLD");
}
}
You should be careful hard coding the .OST path like that. Something like the below would be better:
string ostPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), #"Microsoft\Outlook");
Edit
An better example of replaceOutlook(). Still needs work but better illustrates how this works for OP.
static public void replaceOutlook()
{
// OST PATH
string ostPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), #"Microsoft\Outlook");
// LIST OF FILE PATHS IN OST PATH
string[] fileEntries = Directory.GetFiles(ostPath);
try
{
// CHECK EACH FILE PATH
foreach (string fileName in fileEntries)
{
// IS IT AN OST?
if (Path.GetExtension(fileName).ToLower() == ".ost")
{
// TRY AND DELETE OLD FILE, WON'T THROW EXCEPTION IF FILE DOESN'T EXIST
File.Delete(fileName + ".OLD");
// RENAME FILE
File.Move(fileName, fileName + ".OLD");
}
}
}
catch
{
// Blah blah....
}
}
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;
}