C# Deleting Files - IOException handling - c#

In reference to Deleting All Files how can we handle IO.Exceptions to quietly "skip" those files that the delete can't do? Should we use a try/catch or is there something built-in?
Looks like a simple question but I'm actually having trouble finding a solution for it on the net...

try:
public void DeleteDirectoryFiles(DirectoryInfo dirInfo)
{
foreach(FileInfo files in dirInfo.GetFiles())
{
try
{
files.Delete();
}
catch(IOException ex)
{
// code to handle
}
}
}

Of course. To update the code from the original answer by John Hartsock:
public void DeleteDirectoryFolders(DirectoryInfo dirInfo, bool ignoreIfFailed = false){
foreach (DirectoryInfo dirs in dirInfo.GetDirectories())
{
try
{
dirs.Delete(true);
}
catch (IOException)
{
if (!ignoreIfFailed)
{
throw;
}
}
}
}
public void DeleteDirectoryFiles(DirectoryInfo dirInfo, bool ignoreIfFailed = false) {
foreach(FileInfo files in dirInfo.GetFiles())
{
try
{
files.Delete();
}
catch (IOException)
{
if (!ignoreIfFailed)
{
throw;
}
}
}
}
public void DeleteDirectoryFilesAndFolders(string dirName, bool ignoreIfFailed = false) {
DirectoryInfo dir = new DirectoryInfo(dirName);
DeleteDirectoryFiles(dir, ignoreIfFailed);
DeleteDirectoryFolders(dir, ignoreIfFailed);
}
You can call it like this:
DeleteDirectoryFilesAndFolders(folder, true); // ignore on error
DeleteDirectoryFilesAndFolders(folder, false); // throw exception
DeleteDirectoryFilesAndFolders(folder); // throw exception

The only way to handle an exception quietly would be a try catch with nothing in the catch block.
Be sure to only catch the exception you're expecting though (i.e., catch (IOException)) else you might mask some other problem that you weren't aware of.

Related

Deleting Files - Skip Files in Use

I'm trying to delete the files in a directory, but I get errors when attempting to remove the files which are currently in use. Is there a way to skip the files that are currently in use and delete the rest of them? Thanks.
foreach(var file in Directory.GetFiles(tempPath))
{
File.Delete(file);
}
That's the code I have so far, not sure how to go about this.
you can check by try catch
private bool IsLocked(string filePath)
{
FileInfo f = new FileInfo(filePath);
FileStream stream = null;
try
{
stream = f.Open(FileMode.Open, FileAccess.Read, FileShare.None);
}
catch (IOException ex)
{
return true;
}
finally
{
if (stream != null)
stream.Close();
}
return false;
}
public void RemoveFile(string folderPath)
{
foreach (var file in Directory.GetFiles(folderPath))
{
if (!IsLocked(file))
{
File.Delete(file);
}
}
}
I think the easier way is surrounding your code with a try-catch block. Something like this:
foreach(var file in Directory.GetFiles(tempPath))
{
try
{
File.Delete(file);
}
catch (Exception)
{
//Decide what you want to do here, you can either
//ask user to retry if the file is in use
//Or ignore the failure and continue, or...
}
}
Wrap File.Delete in a try { } catch block

How to implement "retry/abort" mechanism for writing files that may be used by another process?

This is really short question. I don't understand try-catch mechanism completely.
This is my current code:
public static void WriteText(string filename, string text)
{
try
{
System.IO.StreamWriter file = new System.IO.StreamWriter(filename);
file.Write(text);
file.Close();
}
catch(Exception exc)
{
MessageBox.Show("File is probably locked by another process.");
}
}
Background:
Im writing application that shares configuration files with another application.
I need some dialog messagebox with "retry" and "abort" buttons, when that file is used by other application. When that message will appear - I will close that other application and I will try to rewrite that file again by pressing "Retry" button.
Whatr we have is using a counter for re-tries and possibly a thread sleep.
So something like
int tries = 0;
bool completed = false;
while (!completed)
{
try
{
System.IO.StreamWriter file = new System.IO.StreamWriter(filename);
file.Write(text);
file.Close();
completed = true;
}
catch(Exception exc)
{
tries++;
//You could possibly put a thread sleep here
if (tries == 5)
throw;
}
}
Even though there's a good answer already I'll submit one that's more tuned towards the OP's question (let the user decide instead of using a counter).
public static void WriteText(string filename, string text)
{
bool retry = true;
while (retry)
{
try
{
System.IO.StreamWriter file = new System.IO.StreamWriter(filename);
file.Write(text);
file.Close();
retry=false;
}
catch(Exception exc)
{
MessageBox.Show("File is probably locked by another process.");
// change your message box to have a yes or no choice
// yes doesn't nothing, no sets retry to false
}
}
}
If you need more info on how to implement the messagebox check out the following links;
http://msdn.microsoft.com/en-us/library/0x49kd7z.aspx
MessageBox Buttons?
I would do it like that:
public static void WriteText(string filename, string text, int numberOfTry = 3, Exception ex = null)
{
if (numberOfTry <= 0)
throw new Exception("File Canot be copied", ex);
try
{
var file = new System.IO.StreamWriter(filename);
file.Write(text);
file.Close();
}
catch (Exception exc)
{
WriteText(filename,text,--numberOfTry,ex);
}
}
I like it more like this (example tries to save a RichTextBox on close and allows retrying save or aborting close):
protected override void OnClosing(CancelEventArgs e)
{
if (richTextBox_Query.Modified)
{
DialogResult result;
do
try
{
richTextBox_Query.SaveFile(
Path.ChangeExtension(Application.ExecutablePath, "sql"),
RichTextBoxStreamType.UnicodePlainText);
result = DialogResult.OK;
richTextBox_Query.Modified = false;
}
catch (Exception ex)
{
result = MessageBox.Show(ex.ToString(), "Exception while saving sql query",
MessageBoxButtons.AbortRetryIgnore);
e.Cancel = result == DialogResult.Abort;
}
while (result == DialogResult.Retry);
}
base.OnClosing(e);
}

How to throw exception to next catch?

I want to throw an exception at next catch, (I attached image)
Anybody know how to do this?
C# 6.0 to the rescue!
try
{
}
catch (Exception ex) when (tried < 5)
{
}
You can't, and trying to do so suggests that you've got too much logic in your catch blocks, or that you should refactor your method to only do one thing. If you can't redesign it, you'll have to nest your try blocks:
try
{
try
{
...
}
catch (Advantage.Data.Provider.AdsException)
{
if (...)
{
throw; // Throws to the *containing* catch block
}
}
}
catch (Exception e)
{
...
}
On the other hand, as of C# 6, there are exception filters so you can check a condition before actually catching the exception:
try
{
...
}
catch (Advantage.Data.Provider.AdsException) when (tries < 5)
{
tries++;
// etc
}
// This will catch any exception which isn't an AdsException *or* if
// if the condition in the filter isn't met.
catch (Exception e)
{
...
}
One possibility is nesting the try/catch clause:
try
{
try
{
/* ... */
}
catch(Advantage.Data.Provider.AdsException ex)
{
/* specific handling */
throw;
}
}
catch(Exception ex)
{
/* common handling */
}
there is also another way - using only your general catch statement and checking the exception type yourself:
try
{
/* ... */
}
catch(Exception ex)
{
if(ex is Advantage.Data.Provider.AdsException)
{
/* specific handling */
}
/* common handling */
}
This answer is inspired by Honza Brestan's answer:
}
catch (Exception e)
{
bool isAdsExc = e is Advantage.Data.Provider.AdsException;
if (isAdsExc)
{
tried++;
System.Threading.Thread.Sleep(1000);
}
if (tried > 5 || !isAdsExc)
{
txn.Rollback();
log.Error(" ...
...
}
}
finally
{
It's ugly to have two try blocks nested inside each other.
If you need to use properties of the AdsException, use an as cast instead of is.

Can I not catch a specific or custom exception?

I dont want to catch some exception. Can I do it somehow?
Can I say something like this:
catch (Exception e BUT not CustomExceptionA)
{
}
?
try
{
// Explosive code
}
catch (CustomExceptionA){ throw; }
catch (Exception ex)
{
//classic error handling
}
try
{
}
catch (Exception ex)
{
if (ex is CustomExceptionA)
{
throw;
}
else
{
// handle
}
}
Starting with C# 6, you can use an exception filter:
try
{
// Do work
}
catch (Exception e) when (!(e is CustomExceptionA))
{
// Catch anything but CustomExceptionA
}
You can filter it:
if (e is CustomExceptionA) throw;
And of course you can catch it and rethrow it:
try
{
}
catch (CustomExceptionA) { throw; }
catch (Exception ex) { ... }
First off, it's bad practice to catch Exception unless you log and re-throw it. But if you must, you need to catch your custom exception and re-throw it like so:
try
{
}
catch (CustomExceptionA custome)
{
throw custome;
}
catch (Exception e)
{
// Do something that hopefully re-throw's e
}
After being schooled by #Servy in the comments, I thought of a solution that'll let you do [what I think] you want to do. Let's create a method IgnoreExceptionsFor() that looks like this:
public void PreventExceptionsFor(Action actionToRun())
{
try
{
actionToRun();
}
catch
{}
}
This can then be called like this:
try
{
//lots of other stuff
PreventExceptionsFor(() => MethodThatCausesTheExceptionYouWantToIgnore());
//other stuff
}
catch(Exception e)
{
//do whatever
}
That way, every line except for the one with PreventExceptionsFor() will throw exceptions normally, while the one inside PreventExceptionsFor() will get quietly passed over.

Better way to write retry logic without goto [duplicate]

This question already has answers here:
Cleanest way to write retry logic?
(30 answers)
Closed 9 years ago.
Is there a better way to write this code without using goto? It seems awkward, but I can't think of a better way. I need to be able to perform one retry attempt, but I don't want to duplicate any code.
public void Write(string body)
{
bool retry = false;
RetryPoint:
try
{
m_Outputfile.Write(body);
m_Outputfile.Flush();
}
catch (Exception)
{
if( retry )
throw;
// try to re-open the file...
m_Outputfile = new StreamWriter(m_Filepath, true);
retry = true;
goto RetryPoint;
}
}
Here is the basic logic that I would use instead of a goto statement:
bool succeeded = false;
int tries = 2;
do
{
try
{
m_Outputfile = new StreamWriter(m_Filepath, true);
m_Outputfile.Write(body);
m_Outputfile.Flush();
succeeded = true;
}
catch(Exception)
{
tries--;
}
}
while (!succeeded && tries > 0);
I just added # of tries logic, even though the original question didn't have any.
#Michael's answer (with a correctly implemented out catch block) is probably the easiest to use in your case, and is the simplest. But in the interest of presenting alternatives, here is a version that factors the "retry" flow control into a separate method:
// define a flow control method that performs an action, with an optional retry
public static void WithRetry( Action action, Action recovery )
{
try {
action();
}
catch (Exception) {
recovery();
action();
}
}
public void Send(string body)
{
WithRetry(() =>
// action logic:
{
m_Outputfile.Write(body);
m_Outputfile.Flush();
},
// retry logic:
() =>
{
m_Outputfile = new StreamWriter(m_Filepath, true);
});
}
You could, of course, improve this with things like retry counts, better error propagation, and so on.
Michael's solution doesn't quite fulfill the requirements, which are to retry a fixed number of times, throwing the last failure.
For this, I would recommend a simple for loop, counting down. If you succeed, exit with break (or, if convenient, return). Otherwise, let the catch check to see if the index is down to 0. If so, rethrow instead of logging or ignoring.
public void Write(string body, bool retryOnError)
{
for (int tries = MaxRetries; tries >= 0; tries--)
{
try
{
_outputfile.Write(body);
_outputfile.Flush();
break;
}
catch (Exception)
{
if (tries == 0)
throw;
_outputfile.Close();
_outputfile = new StreamWriter(_filepath, true);
}
}
}
In the example above, a return would have been fine, but I wanted to show the general case.
What if you put it in a loop? Something similar to this, maybe.
while(tryToOpenFile)
{
try
{
//some code
}
catch
{
}
finally
{
//set tryToOpenFile to false when you need to break
}
}
public void Write(string body, bool retryOnError)
{
try
{
m_Outputfile.Write(body);
m_Outputfile.Flush();
}
catch (Exception)
{
if(!retryOnError)
throw;
// try to re-open the file...
m_Outputfile = new StreamWriter(m_Filepath, true);
Write(body, false);
}
}
Try something like the following:
int tryCount = 0;
bool succeeded = false;
while(!succeeded && tryCount<2){
tryCount++;
try{
//interesting stuff here that may fail.
succeeded=true;
} catch {
}
}
with a boolean
public void Write(string body)
{
bool NotFailedOnce = true;
while (true)
{
try
{
_outputfile.Write(body);
_outputfile.Flush();
return;
}
catch (Exception)
{
NotFailedOnce = !NotFailedOnce;
if (NotFailedOnce)
{
throw;
}
else
{
m_Outputfile = new StreamWriter(m_Filepath, true);
}
}
}
}

Categories

Resources