suppose we have c:\\d1\\d2\\d3\\... where there are many files and directories in d3.
we want to move all items in d3 to c:\\d1\\new\\.
how to do it clean and safe?
c:\\d1\\new exists!
If c:\d1\new does not exist yet, and you don't want to keep an empty c:\d1\d2\d3 folder afterward, you can use the Directory.Move() method:
using System.IO;
try {
Directory.Move(#"c:\d1\d2\d3", #"c:\d1\new");
} catch (UnauthorizedAccessException) {
// Permission denied, recover...
} catch (IOException) {
// Other I/O error, recover...
}
If c:\d1\new does exist, you'll have to iterate over the contents of c:\d1\d2\d3 and move its files and folders one by one:
foreach (string item in Directory.GetFileSystemEntries(#"c:\d1\d2\d3")) {
string absoluteSource = Path.Combine(#"c:\d1\d2\d3", item);
string absoluteTarget = Path.Combine(#"c:\d1\new", item);
if (File.GetAttributes(absoluteSource) & FileAttributes.Directory != 0) {
Directory.Move(absoluteSource, absoluteTarget);
} else {
File.Move(absoluteSource, absoluteTarget);
}
}
Use Directory.Move
Also, MSDN has a handy table of what functions to use for Common I/O Tasks which is a good reference for questions like this.
try
{
System.IO.Directory.Move(#"c:\d1\d2\d3\", #"c:\d1\new\");
}
catch(...)
{
}
The Move method can throw any of the following exceptions that depending on your usage may or may not be thrown. So you need to code the exception handler in a manner that suits your application.
System.IO.IOExeption
System.UnauthorizedAccessException
System.ArgumentException
System.ArgumentNullException
System.IO.PathToLongException
System.IO.DirectoryNotFoundException
As an general example (you probably don't want/need to display message boxes on errors):
try
{
System.IO.Directory.Move(#"c:\d1\d2\d3\", #"c:\d1\new\");
}
catch (System.UnauthorizedAccessException)
{
MessageBox.Show("You do not have access to move this files/directories");
}
catch(System.IO.DirectoryNotFoundException)
{
MessageBox.Show("The directory to move files/directories from was not found")
}
catch
{
MessageBox.Show("Something blew up!");
}
Finally, it is worth mentioning that the call to Move will block the current thread until the move is complete. So if you are doing this from a UI it will block the UI until the copy is complete. This might take some time depending on how many files/directories are being move. Therefore it might be prudent to run this in a seperate thread and/or display a cycling progress bar.
Use Directory.Move.
Moves a file or a directory and its contents to a new location.
Related
I'm working with the following code, but I'm not sure how is the proper way to do it.
try
{
// Do code for Try1
Console.WriteLine("Try1 Successful");
}
try
{
// If try1 didn't work. Do code for Try2
Console.WriteLine("Try2 Successful");
}
try
{
// If try2 didn't work. Do code for Try3
Console.WriteLine("Try3 Successful");
}
catch (Exception)
{
// If try1, 2 and 3 didn't work. print this:
Console.WriteLine("The program failed");
}
What I want is to try 3 different ways of a task, and if the 3 of them fail, print "The program failed", but if one of them is successful, don't do the other ones and continue with the program
Edit:
The task that I am trying to do, is looking for a NETWORK PATH.
The Task 1 will look if a path can be opened, if so OPEN THE DIRECTORY.
If not: Task 2 will look if a second path can be opened, if so OPEN THE DIRECTORY.
If not: Task 3 will look if a third path works, if so OPEN IT.
If not "no paths can be found on this pc"
You can make it without try catch block.
For the simplicity make that Task1, Task2, Task3, have some kind of return types.
For example if they return boolean type. TRUE if Task succededd or FALSE if Task failed.
Or they can return some custom type with boolean result, and string error message. I would not go with nested try catch blocks.
executeTasks() {
Console.WriteLine("Try 1");
if (Task1()) return;
Console.WriteLine("Try 2");
if (Task2()) return;
Console.WriteLine("Try 3");
if (Task3()) return;
Console.WriteLine("The program failed");
}
Hopefully this snippet can be easily adapted to meet your needs.
namespace StackOverflow69019117TryCatch
{
using System;
using System.IO;
public class SomeClass
{
public void MainMethod()
{
var paths = new string[] {
#"C:\Users\otherUser\Documents", // exists but I don't have access to it
#"C:\temp", // exists but doesn't contain the folderToSearchFor subfolder
#"Z:\doesntexist", // doesn't exist
};
foreach (var path in paths)
{
Console.WriteLine($"Trying with path {path}");
if (this.ProcessDirectory(path, "folderToSearchFor"))
{
// We've succeeded so exit the loop
Console.WriteLine($"Succeeded using path {path}");
return;
}
else
{
// We've failed so continue round the loop and hope we succeed next time
Console.WriteLine($"Failed using path {path}");
}
}
}
private bool ProcessDirectory(string directoryPath, string folderToSearchFor)
{
// First, check whether the directory we want to search actually exists.
if (!Directory.Exists(directoryPath))
{
// Then the directory we're trying to search in doesn't exist.
// Return false, no need to incur the overhead of an exception.
Console.WriteLine($"Directory {directoryPath} doesn't exist");
return false;
}
// This doesn't appear to throw an exception if directoryPath isn't accessible to the current user.
// Instead it just returns whatever the current user has access to (which may be an empty array).
var propFolderCandidates = Directory.GetDirectories(directoryPath, $"{folderToSearchFor}*");
// But did it return anything?
// If not then what we're looking for either doesn't exist or the user doesn't have access to it.
if (propFolderCandidates.Length == 0)
{
// Then there's no folder here matching the search path.
// Return false, no need to incur the overhead of an exception.
Console.WriteLine($"Couldn't find folder matching {folderToSearchFor} in {directoryPath}");
return false;
}
var propFolder = propFolderCandidates[0];
// Consider implementng similar checks in Process.Start.
// e.g. if it's reading a file, check whether the file exists first
if (Process.Start(propFolder))
{
Console.WriteLine($"Process.Start succeeded using {directoryPath}");
return true;
}
else
{
Console.WriteLine($"Process.Start failed using {directoryPath}");
return false;
}
}
}
}
As #BionicCode has pointed out in various comments, it's less expensive to check whether an action might throw an exception before performing that action, than it is to perform the action and then handle the exception if it's thrown by the action.
I had to do a bit of digging to establish what happens when Directory.GetDirectories tries to get the subfolders of a folder that the current user doesn't have access to - I was expecting it to throw an exception, but it seems that it doesn't, it just returns an empty array representing the nothing that the current user has access to in that location, so no exception to handle in that scenario.
Throwing and catching of exceptions definitely has its place in .net software, but you should treat it as something to fall back on if something happens which you can't anticipate at design time - if there's a way at design time of detecting that a particular action isn't going to work, then you should detect it and report to the caller that the action they've requested won't work, rather than performing the action and trying to handle any exception it might throw.
There is some wise advice from Microsoft on the subject of best practice for exceptions.
Use exception handling if the event doesn't occur very often, that is, if the event is truly exceptional and indicates an error (such as an unexpected end-of-file). When you use exception handling, less code is executed in normal conditions.
Check for error conditions in code if the event happens routinely and could be considered part of normal execution. When you check for common error conditions, less code is executed because you avoid exceptions.
Hope this is useful :-)
You're gonna have to nest your try-catch blocks:
try {
Console.WriteLine("Try1 successful");
} catch {
try {
Console.WriteLine("Try2 successful");
} catch {
try {
Console.WriteLine("Try3 successful");
} catch {
Console.WriteLine("The program failed");
}
}
}
I have already found a way, to be honest I don't know if this is the best way, but totally works.
The solution was to nest a few try-catch(exception)
This is what I am doing...
try
{
try
{
//Check if PROP can be found inside initial path A
string[] PROP_FOLDER = Directory.GetDirectories(Full_PathA, $"{PROP}*");
Process.Start(PROP_FOLDER[0]);
//Open PROP in path A and RETURN
status_label.Text = " Found it!";
status_label.ForeColor = Color.LimeGreen;
}
catch (Exception) //If an error occurs on path A
{
try
{
//Check if PROP can be found inside initial path B
string[] PROP_FOLDER = Directory.GetDirectories(Full_PathB, $"{PROP}*");
Process.Start(PROP_FOLDER[0]);
//Open PROP in path B and RETURN
status_label.Text = " Found it!";
status_label.ForeColor = Color.LimeGreen;
}
catch (Exception) //If an error occurs on path B
{
//Check if PROP can be found inside initial path C
string[] PROP_FOLDER = Directory.GetDirectories(Full_PathC, $"{PROP}*");
Process.Start(PROP_FOLDER[0]);
//Open PROP in path C and RETURN
status_label.Text = " Found it!";
status_label.ForeColor = Color.LimeGreen;
}
}
}
catch (Exception) //If PROP cannot be found on any of those paths, the PROP doesn't exist
{
status_label.Text = " Not Found!";
status_label.ForeColor = Color.Red;
}
On my web API, I want to delete a folder after my return statement.
public string Post(HttpRequestMessage request)
{
//Do cool stuff with request
try
{
return "10.0.2.2:8080/myFolder/index.html";
}
finally
{
Thread.Sleep(60000);
Directory.Delete(myFolder, true);
}
}
What I expected is that the device making the POST could get the return statement and load the html file. After a minute, we delete this file to free space on the server.
What happens is that the return statement is actually sent after the finally statement.
How can I run code after a return statement with delay, without delaying the return?
There is no way to do that and it would be bad anyway, since you would keep resources (webserver threads for example) busy waiting.
Write another process (preferably a Windows service if you are on Windows) that checks the directory periodically and deletes all files of a certain age.
you can't execute code after return
in my opinion you can check files if the file created before 1m delete it
DirectoryInfo objDirectoryInfo = new
DirectoryInfo(Server.MapPath("~/files"));
foreach (FileInfo File in objDirectoryInfo.GetFiles) {
if ((File.LastAccessTime < DateTime.Now.AddMinutes(-1))) {
File.Delete();
}
}
This question already has answers here:
Why is try {...} finally {...} good; try {...} catch{} bad?
(20 answers)
Closed 9 years ago.
difference between try...catch and try....finally ? in asp.net(C#)
like when i want to catch error like 1/0 then i put code in try block and put exception object in catch block like response.write("ERROR:"+ ex.Message) but advisors told me that it isn't a good practice to put catch always, it absorbs error without notifying ????? ehhhhh ? but it did via ex.Message , so why ?
and what does try....finally do ? i know that it is used to release resources but of what use is TRY if exception can't be catched ?
try/catch/finally:
try
{
// open some file or connection
// do some work that could cause exception
}
catch(MyException ex)
{
// do some exception handling: rethrow with a message, log the error, etc...
// it is not a good practice to just catch and do nothing (swallow the exception)
}
finally
{
// do some cleanup to close file/connection
// guaranteed to run even if an exception happened in try block
// if there was no finally, and exception happened before cleanup in your try block, file could stay open.
}
Try/Finally:
try
{
// open some file/connection
// do some work, where you're not expecting an exception
// or, you don't want to handle the exception here, rather just let it go to the caller, so no need for a catch
}
finally
{
// do cleanup, guaranteed to go in this finally block
}
Eveything that is enclosed in your finally block is ensured to be executed, and it could be useful in these 2 concrete cases at least :
Sometimes you decide to call return in the middle of your try block and get back to the caller : finally ease the process of releasing ressources here, you don't have to write some specific code to go directly to the end of your method.
Sometimes you want to let an exception go up (by not catching it) and maybe being caught at a higher level (because it is not the appropriate place to handle it properly for example). Again finally ensures your resources are released and the exception continue its path.
Maybe you can see finally as a tool helping developpers to do things they're obliged to do with less effort. On the other side, catch is dedicated to handle errors.
Both keywords are dedicated to flow control, but they don't have the same purpose and they can be used one without each other (and often are!). It depends on your needs.
Finally is always executed whether there is an exception or not. This can be handy if you want to be absolutely certain that something is cleaned up. Example:
void ReadFile(int index)
{
// To run this code, substitute a valid path from your local machine
string path = #"c:\users\public\test.txt";
System.IO.StreamReader file = new System.IO.StreamReader(path);
char[] buffer = new char[10];
try
{
file.ReadBlock(buffer, index, buffer.Length);
}
catch (System.IO.IOException e)
{
Console.WriteLine("Error reading from {0}. Message = {1}", path, e.Message);
}
finally
{
if (file != null)
{
file.Close();
}
}
// Do something with buffer...
}
If you didn't have a finally in there it would be possible that the file would not be closed properly if an error occurred. Regardless of whether an error occurs or not, you want the file to be closed when you are done.
Consider the alternative:
void ReadFile(int index)
{
// To run this code, substitute a valid path from your local machine
string path = #"c:\users\public\test.txt";
System.IO.StreamReader file = new System.IO.StreamReader(path);
char[] buffer = new char[10];
try
{
file.ReadBlock(buffer, index, buffer.Length);
file.Close();
}
catch (System.IO.IOException e)
{
Console.WriteLine("Error reading from {0}. Message = {1}", path, e.Message);
}
}
If you error out on ReadBlock the file will not be properly closed.
I read several articles regarding good practices in exception handling. Most of it tackled unexpected exceptions yet expected by the author. I just want to clarify and eliminate possible bad practices that I could be doing. Since I already expect these problems to happen already, I assume throwing an exception is a bit redundant.
Let's say I have this code :
string fileName = Path.Combine(Application.StartupPath, "sometextfile.txt");
// There's a possibility that the file doesn't exist <<<<<<<<<<<<<<<<<<<<<
if (!File.Exists(fileName))
{
// Do something here
return;
}
// Therefore, this will return an exception
using (StreamReader file =
new StreamReader(fileName))
{
// Some code here
}
Naturally, what I would do is to inform the user with a MessageBox saying "File not found". Is there an efficient or a better way of doing this?
Another idea that I have is to create an enum which contains expected error codes then create a method which will call a MessageBox showing the error message for that specific situation :
enum ErrorCodes {null, zero, ...}
public void showError(ErrorCodes error)
{
string message;
switch (error)
{
case ErrorCode.null:
{
message = "value cannot be null";
break;
}
case ErrorCode.zero:
{
message = "cannot divide by zero";
break;
}
}
MessageBox.Show(message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
These things are never easy. By definition an exception is (like the Spanish Inquisition) never expected. In your first example the file might exist when you call File.Exist, but then not exist when you try to open it (file deleted, network failed, thumb drive pulled, etc.). As far as a best practice: protect yourself where you can, catch only the exceptions you know how to handle and hope for the best. Programs will fail and the very best thing you can do is make sure that unhandled failures are communicated as clearly as possible to the user of the code (the heart of your second example).
Communicating a failure depends greatly on the what the code does and who is using it. MessageBoxes are often used but generally not 'useful', because if the cause of the error isn't clear to the user about the only thing they can do is send you a jpg image (that's a best case :-D). Providing a way to log problems and/or a custom dialog that allows users to cut/paste information (like a stack trace) is much more useful. Think about the case where a user selects a file and there is a network hiccup. They tell you they got this error about the file not being found, but when you or they look it's there because the network is working correctly by that time. A simple "file not found" message does give you enough information and so you have to tell the user "I don't know, glad it works now" ... this does not inspire confidence. Best practice here is to leave yourself enough 'breadcrumbs' to at least have a rough idea about what has happened. Even something like having a full file path can give you the clues you need to figure out what went wrong.
If the code that is trying to access the file is on the front end, for example an event handler for an on-click, then it's OK to check for the error situation, display a message and return.
If I understand your question correctly you want to know whether you should do this:
public void button_Click() {
if(!File.Exists(textBox.Text)) {
MessageBox.Show("Could not find the file");
return;
}
ProcessFile(textBox.Text); // would have thrown an exception if the file didn't exist
}
That would be fine, except if ProcessFile throws any other kind of Exception it won't be handled.
You could do this:
public void button_Click() {
try {
ProcessFile(textBox.Text); // throwns an exception if the file didn't exist
} catch(Exception ex) {
MessageBox.Show(GetUserMessage(ex));
return;
}
}
In my opinion it's better to do both:
public void button_Click() {
try {
if(!File.Exists(textBox.Text)) {
MessageBox.Show("Could not find the file");
return;
}
ProcessFile(textBox.Text); // throwns an exception if the file didn't exist
} catch(Exception ex) {
MessageBox.Show(GetUserMessage(ex));
return;
}
}
This way you can provide the most specific message to the user relevant to what he was doing at this point. For example if he was trying to open an Excel file you could say "Could not find the Excel file you wanted to import".
This also works in case the file was deleted or renamed between the point you checked and the point you tried to process the file.
Alternatively you could accomplish something similar with this:
public void button_Click() {
try {
if(!File.Exists(textBox.Text)) {
throw new UserException("Could not find the file");
}
ProcessFile(textBox.Text); // throwns an exception if the file didn't exist
} catch(Exception ex) {
MessageBox.Show(GetUserMessage(ex));
return;
}
}
In this case you would create your own Exception class UserException and just pass that message along without translating it. This would allow you to reuse the same code you use to display a message.
Exceptions in Classes
If the error occurs in some class library then you should throw an exception. The purpose of an exception is that an error can't go unnoticed.
For example you shouldn't want this:
class MyFileHandler {
public void OpenFile(string fileName) {
if(!File.Exists(fileName)) return;
// do stuff
}
public void DoStuff() {
// do stuff
}
}
Now if a developer called myFileHandlerInstance.OpenFile("note.txt") he would assumed it worked. You could return a boolean, like so:
class MyFileHandler {
public bool OpenFile(string fileName) {
if(!File.Exists(fileName)) return false;
// do stuff
return true;
}
public void DoStuff() {
// do stuff
}
}
But now you are relying on the developer checking that value, this used to be a common method but errors got ignored and overlooked which is why Exceptions became better practice.
As far as what to display to the user, you really shouldn't display the Exception message directly, those messages are intended for developers not users. I suggest a method that takes an exception object and returns the best message, like so:
public string GetUserErrorMessage(Exception ex) {
if(ex is FileLoadException) {
var fileLoadException = (FileLoadException)ex;
return "Sorry but we failed to load the file: " + fileLoadException.FileName;
}
}
You can inspect the Exception properties for details including error codes if you like. Also I suggest capturing the actual exception details somewhere for your own debugging purposes, somewhere where it's not visible to the user.
When a file is being copied to the file watcher folder, how can I identify whether the file is completely copied and ready to use? Because I am getting multiple events during file copy. (The file is copied via another program using File.Copy.)
When I ran into this problem, the best solution I came up with was to continually try to get an exclusive lock on the file; while the file is being written, the locking attempt will fail, essentially the method in this answer. Once the file isn't being written to any more, the lock will succeed.
Unfortunately, the only way to do that is to wrap a try/catch around opening the file, which makes me cringe - having to use try/catch is always painful. There just doesn't seem to be any way around that, though, so it's what I ended up using.
Modifying the code in that answer does the trick, so I ended up using something like this:
private void WaitForFile(FileInfo file)
{
FileStream stream = null;
bool FileReady = false;
while(!FileReady)
{
try
{
using(stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None))
{
FileReady = true;
}
}
catch (IOException)
{
//File isn't ready yet, so we need to keep on waiting until it is.
}
//We'll want to wait a bit between polls, if the file isn't ready.
if(!FileReady) Thread.Sleep(1000);
}
}
Here is a method that will retry file access up to X number of times, with a Sleep between tries. If it never gets access, the application moves on:
private static bool GetIdleFile(string path)
{
var fileIdle = false;
const int MaximumAttemptsAllowed = 30;
var attemptsMade = 0;
while (!fileIdle && attemptsMade <= MaximumAttemptsAllowed)
{
try
{
using (File.Open(path, FileMode.Open, FileAccess.ReadWrite))
{
fileIdle = true;
}
}
catch
{
attemptsMade++;
Thread.Sleep(100);
}
}
return fileIdle;
}
It can be used like this:
private void WatcherOnCreated(object sender, FileSystemEventArgs e)
{
if (GetIdleFile(e.FullPath))
{
// Do something like...
foreach (var line in File.ReadAllLines(e.FullPath))
{
// Do more...
}
}
}
I had this problem when writing a file. I got events before the file was fully written and closed.
The solution is to use a temporary filename and rename the file once finished. Then watch for the file rename event instead of file creation or change event.
Note: this problem is not solvable in generic case. Without prior knowledge about file usage you can't know if other program(s) finished operation with the file.
In your particular case you should be able to figure out what operations File.Copy consist of.
Most likely destination file is locked during whole operation. In this case you should be able to simply try to open file and handle "sharing mode violation" exception.
You can also wait for some time... - very unreliable option, but if you know size range of files you may be able to have reasonable delay to let Copy to finish.
You can also "invent" some sort of transaction system - i.e. create another file like "destination_file_name.COPYLOCK" which program that copies file would create before copying "destination_file_name" and delete afterward.
private Stream ReadWhenAvailable(FileInfo finfo, TimeSpan? ts = null) => Task.Run(() =>
{
ts = ts == null ? new TimeSpan(long.MaxValue) : ts;
var start = DateTime.Now;
while (DateTime.Now - start < ts)
{
Thread.Sleep(200);
try
{
return new FileStream(finfo.FullName, FileMode.Open);
}
catch { }
}
return null;
})
.Result;
...of course, you can modify aspects of this to suit your needs.
One possible solution (It worked in my case) is to use the Change event. You can log in the create event the name of the file just created and then catch the change event and verify if the file was just created. When I manipulated the file in the change event it didn't throw me the error "File is in use"
If you are doing some sort of inter-process communication, as I do, you may want to consider this solution:
App A writes the file you are interested in, eg "Data.csv"
When done, app A writes a 2nd file, eg. "Data.confirmed"
In your C# app B make the FileWatcher listen to "*.confirmed" files. When you get this event you can safely read "Data.csv", as it is already completed by app A.
(Edit: inspired by commets) Delete the *.confirmed filed with app B when done processing the "Data.csv" file.
I have solved this issue with two features:
Implement the MemoryCache pattern seen in this question: A robust solution for FileSystemWatcher firing events multiple times
Implement a try\catch loop with a timeout for access
You need to collect average copy times in your environment and set the memory cache timeout to be at least as long as the shortest lock time on a new file. This eliminates duplicates in your processing directive and allows some time for the copy to finish. You will have much better success on first try, which means less time spent in the try\catch loop.
Here is an example of the try\catch loop:
public static IEnumerable<string> GetFileLines(string theFile)
{
DateTime startTime = DateTime.Now;
TimeSpan timeOut = TimeSpan.FromSeconds(TimeoutSeconds);
TimeSpan timePassed;
do
{
try
{
return File.ReadLines(theFile);
}
catch (FileNotFoundException ex)
{
EventLog.WriteEntry(ProgramName, "File not found: " + theFile, EventLogEntryType.Warning, ex.HResult);
return null;
}
catch (PathTooLongException ex)
{
EventLog.WriteEntry(ProgramName, "Path too long: " + theFile, EventLogEntryType.Warning, ex.HResult);
return null;
}
catch (DirectoryNotFoundException ex)
{
EventLog.WriteEntry(ProgramName, "Directory not found: " + theFile, EventLogEntryType.Warning, ex.HResult);
return null;
}
catch (Exception ex)
{
// We swallow all other exceptions here so we can try again
EventLog.WriteEntry(ProgramName, ex.Message, EventLogEntryType.Warning, ex.HResult);
}
Task.Delay(777).Wait();
timePassed = DateTime.Now.Subtract(startTime);
}
while (timePassed < timeOut);
EventLog.WriteEntry(ProgramName, "Timeout after waiting " + timePassed.ToString() + " seconds to read " + theFile, EventLogEntryType.Warning, 258);
return null;
}
Where TimeoutSeconds is a setting that you can put wherever you hold your settings. This can be tuned for your environment.