I am making a software that will move files from the downloads folder to a specific sub folder in a directory. The sub folder is selected by the user by a combobox. I keep getting this error: System.IO.IOException: Cannot create a file when that file already exists. Also, these error come up on people's computer who install my program...exceptions and things. How do i turn it off. Also, why do i get this error? Here is my code:
string pathUser4 = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
string pathDownload4 = (pathUser4 + #"\Downloads\");
string sourceFile = pathDownload4 + listBox1.Text;
string pathdoc5 = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string pathDownload5 = (pathdoc5 + #"\iracing\setups\");
string destinationFile = pathDownload5 + comboBox1.Text;
File.Move(sourceFile, destinationFile);
if (comboBox1.Text == "Select File Destination")
{
MessageBox.Show("Please Select A Destination Folder", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
Each File.Move should be wrapped in a try/catch block as you can never expect an IO operation to execute without error. It could be something as simple as the user having a file handle open, or the file existing in the destination folder, either way, you don't want a single file to throw an exception that stops the entire operation. You will want to catch the exceptions and log them either to an error log file or to the event log, this way you can see the errors that occurred but it will not interrupt anything.
Secondly, for any desktop application I would add global error handling to log any uncaught errors. You can do this by putting this code at the beginning of your program,
AppDomain.CurrentDomain.UnhandledException += (a, exception) => File.AppendAllText("errorlog.txt", exception.ToString() + "\n"
This will keep the user from ever seeing ugly exceptions being thrown. Also be sure you are not giving the users the .pdb files as this will cause exceptions to contain paths of the computer it was compiled on which can contain your username and other sensitive information you wouldn't want a client to see.
You can register the global exception handling when the main window is initialized, you want it to be the first thing you do before any thing else because again you never know when an exception will be thrown so you have to think defensively.
public partial class MainWindow : Window
{
public MainWindow()
{
AppDomain.CurrentDomain.UnhandledException += (a, exception) => File.AppendAllText("errorlog.txt", exception.ToString() + "\n");
InitializeComponent();
}
}
C# uses exceptions extensively so it will be good concept for you to study up on if you are not familiar with this type of error handling. All exceptions derive from the Exception class so when you write catch (Exception e) this will catch all exceptions (because a base reference can hold an object of a derived type), however if you know the specific exception a method will throw you can catch a more specific exception (always before the more general catch) and handle it in a specific way. In this example you may have an IOException from the File.Move() that you want to catch and handle differently.
try
{
string pathUser4 = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
string pathDownload4 = (pathUser4 + #"\Downloads\");
string sourceFile = pathDownload4 + listBox1.Text;
string pathdoc5 = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string pathDownload5 = (pathdoc5 + #"\iracing\setups\");
string destinationFile = pathDownload5 + comboBox1.Text;
File.Move(sourceFile, destinationFile);
if (comboBox1.Text == "Select File Destination")
{
MessageBox.Show("Please Select A Destination Folder", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
catch (Exception e)
{
File.AppendAllText("ErrorLog.txt", e.ToString() + "\n");
}
The example code from MSDN for File.Move should get you pointed at the various things you need to deal with, such as an already existing file and basic error handling.
using System;
using System.IO;
class Test
{
public static void Main()
{
string path = #"c:\temp\MyTest.txt";
string path2 = #"c:\temp2\MyTest.txt";
try
{
if (!File.Exists(path))
{
// This statement ensures that the file is created,
// but the handle is not kept.
using (FileStream fs = File.Create(path)) {}
}
// Ensure that the target does not exist.
if (File.Exists(path2))
File.Delete(path2);
// Move the file.
File.Move(path, path2);
Console.WriteLine("{0} was moved to {1}.", path, path2);
// See if the original exists now.
if (File.Exists(path))
{
Console.WriteLine("The original file still exists, which is unexpected.");
}
else
{
Console.WriteLine("The original file no longer exists, which is expected.");
}
}
catch (Exception e)
{
Console.WriteLine("The process failed: {0}", e.ToString());
}
}
}
The error may caused by your code, or by some invalid input.
As #Despertar mentioned, I suggest all the program include error handling and log features in your code. It will be very helpful for your debug.
But I suggest use open source log library, not do it by yourself. For example, log4net, NLog, etc.
Related
EDIT:
My problem has been solved thanks to the user Chris Larabell, thank you to all that responded.
The issue that is happening with my code is that when the said file is not present in the Desktop directory, the console will close and will not go to the else statement for what happens when the file is not present. When the file is present however, the console will work completely fine, it is just the else statement.
Here is my code that is being used.
if (inputDrive == "search.system")
{
try
{
string Desktop = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
string DeleteFile = #"delete.txt";
string[] fileList = System.IO.Directory.GetFiles(Desktop, DeleteFile);
foreach (string file in fileList)
{
if (System.IO.File.Exists(file))
{
System.IO.File.Delete(file);
Console.WriteLine("File has been deleted");
Console.ReadLine();
}
else
{
Console.Write("File could not be found");
Console.ReadLine();
}
}
}
catch (System.IO.FileNotFoundException)
{
Console.WriteLine("search has encountered an error");
Console.ReadLine();
}
}
What I am trying to accomplish is to find a file through the Desktop directory with the name of 'delete.txt' and to delete it when the user enters "search.system". the console would then say back to you that the file has been deleted. If the file has not been found, it would say that "the file could not be found" back to you through console. If an error would to occur, it would go to catch and say "search has encountered an error"
I also want to say that I am sorry if this code is messy and/or if this is completely wrong from what I am trying to accomplish. I am new to C#, and new to coding in general.
You would want to put an if statement to check that the fileList length is > 0. If the file length is zero, the file was not found. Otherwise, you can proceed to delete the file.
Also, don’t be discouraged as a new coder. Set a breakpoint at the line where you use the GetFiles() method and step (F11) to the next line. Hover your cursor over the fileList variable and see if the number of items in the array is zero.
System.IO.Directory.GetFiles()
It looks like you are simply looking for a specific file by name and deleting it if it exists. You could simplify your code by doing this:
if (inputDrive == "search.system")
{
try
{
string Desktop = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
string DeleteFile = #"delete.txt";
string filePath = System.IO.Path.Combine(Desktop, DeleteFile);
if (System.IO.File.Exists(filePath))
{
System.IO.File.Delete(filePath);
Console.WriteLine("File has been deleted");
Console.ReadLine();
}
else
{
Console.Write("File could not be found");
Console.ReadLine();
}
}
catch (System.Exception ex)
{
Console.WriteLine($"search has encountered an error: {ex}");
Console.ReadLine();
}
}
I have a C# application which uses log4net to write some log outputs in a file names "logfile.txt" residing in the application directory. I want to empty the contents of the file as soon as it reaches a size of 10GB.
For that I'm using a timer which keeps checking whether the size of the file crosses 10GB.
But I cannot perform any operation on "logfile.txt" since it is being used by other threads to write log outputs and it's throwing me,
System.IO.IOException "The process cannot access the file 'C:\Program Files\MyApps\TestApp1\logfile.txt' because it is being used by another process."
Here is the code of the timer which checks the size of the file "logfile.txt"
private void timer_file_size_check_Tick(object sender, EventArgs e)
{
try
{
string log_file_path = "C:\\Program Files\\MyApps\\TestApp1\\logfile.txt";
FileInfo f = new FileInfo(log_file_path);
bool ex;
long s1;
if (ex = f.Exists)
{
s1 = f.Length;
if (s1 > 10737418240)
{
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
File.Delete(log_file_path);
//File.Create(log_file_path).Close();
//File.Delete(log_file_path);
//var fs = new FileStream(log_file_path, FileMode.Truncate);
}
}
else
{
MDIParent.log.Error("Log file doesn't exists..");
}
}
catch (Exception er)
{
MDIParent.log.Error("Exceptipon :: " + er.ToString());
}
}
You shouldn't delete a log file on your own because log4net can do it for you. If you use RollingFileAppender you can specify the maximum file size (maximumFileSize property). Additionally if you set maxSizeRollBackups property to 0, then the log file will be truncated when it reaches the limit. Please look at this question for an example.
I have a try catch statement which handles reading a list of xml files and outputs them to csv files.
Now I want to be able to move faulty xml files to a different folder from the healthy files but am not sure how to do it.
What I have got so far is as below:
bool faultyYN = false;
foreach (string filename in XMLFiles)
{
using (var reader = new StreamReader(filename))
{
string shortFileName = Path.GetFileNameWithoutExtension(filename);
XMLShredder.DataFile df = null;
try
{
var sw = new Stopwatch();
sw.Start();
df = Shredder.ShredDocument(XDocument.Load(reader, LoadOptions.SetLineInfo));
sw.Stop();
var elapsed = sw.ElapsedMilliseconds;
_log.InfoFormat(" Shredded file <{0}> in {1}ms", shortFileName, elapsed);
string outputFileName = Path.Combine(outputDirectory, shortFileName) + ".csv";
sw.Reset();
sw.Start();
using (var writer = new ChunkedShreddedFileWriter(outputFileName))//full file path
{
new DataFileCsvWriter().Write(df,
writer);
}
sw.Stop();
var elapsed2 = sw.ElapsedMilliseconds;
_log.InfoFormat(" Wrote file <{0}> in {1}ms", shortFileName, elapsed2);
}
catch (XmlException e)
{
_log.Error(String.Format("Reading failed due to incorrect structure in XML Document. File Name : <{0}>. Error Message : {1}.", shortFileName, e.Message), e);
faultyYN = true;
}
catch (IOException e)
{
_log.Error(String.Format("Reading failed due to IO Exception. File Name : <{0}>. Error Message : {1}.", shortFileName, e.Message), e);
}
if(bool faultyYN == true)
{
MoveFaultyXML(faultyXMLDirectory, shortFileName);
}
}
TidyUp(XMLFiles);//deletes the files after the process has finished.
}
I have tried adding the Move faulty files to faulty directory after the catch but the files still keep getting deleted.
So basically the method that does not work as I don't know where I should be calling it from is "MoveFaultyXML(faultyXMLDirectory, shortFileName)".
I have read on the net that I shouldn't be using a an exception to branch out but in this case I couldn't think of an alternative solution. The exception has to be thrown for me to know that there is something wrong with the file.
If there is another way of dealing with this which is better practice or if this way works but I am doing it wrong then please help me and I would really appreciate it.
Thanks,
Jetnor.
First solution that comes to my mind would be to:
Move the MoveFaultyXML(faultyXMLDirectory, shortFileName); call to do it within the appropriate catch block:
catch (XmlException e)
{
//log
MoveFaultyXML(faultyXMLDirectory, shortFileName);
}
You don't need the boolean faultyYN.
Now you can create a class representing your XML file (instead of storing just file names in your XMLFiles list):
public class XMLFile
{
public string FileName { get; set; }
public bool Delete { get; set; }
}
And set the Delete flag to 'false' if you move the file.
In the TidyUp delete only files with this flag set to 'true'.
An alternative solution would be to:
Replace foreach() with
for(int i=XMLFiles.Count - 1; i >= 0; i--)
{
string filename = XMLFiles[i];
//the rest of your code
}
Change the catch block with the XMLException to:
catch (XmlException e)
{
//log
MoveFaultyXML(faultyXMLDirectory, shortFileName);
XMLFiles.RemoveAt(i);
}
This way when you get to CleanUp function, any files that were moved are no longer on the list to be deleted.
The `XmlException' is thrown when the XML is incorrect, so it is inside this catch block that you have to call your MoveFaultyXML.
Additional Notes:
Don't add YN to boolean names. Use something like xmlIsFaulty = true. This makes the code easier to read because then you have conditional statements like
if(xmlIsFaulty){MoveFaultyXml();}
which even a non-programmar can understand.
In this code, you're redeclaring the faultyYN variable which should given an error.
if(bool faultyYN == true)
{
MoveFaultyXML(faultyXMLDirectory, shortFileName);
}
After you've declared the variable at the start of the method, you do not need to declare it again.
This is because TidyUp(XMLFiles); still gets executed after your exception is caught, you can move TidyUp(XMLFiles); to within the try block or only call it in catch blocks which are needed.
when deleting files one by one error is generated as "the process cannot access the file ' because it is being used by another process when trying to delete file"
code : any suggestions for delete files like this ?
private void DeleteFilesFromDestination()
{
string consolidatedFolder = System.Configuration.ConfigurationManager.AppSettings["path"].ToString();
foreach (String file in ListBoxDeleteFiles.Items)
{
try
{
// delete each selected files from the specified TargetFolder
if (System.IO.File.Exists(consolidatedFolder + #"\" + System.IO.Path.GetFileName(file)))
{
proc.WaitForExit();
System.IO.File.Delete(consolidatedFolder + #"\" + System.IO.Path.GetFileName(file));
}
}
catch (Exception ex)
{
MessageBox.Show("Error Could not Delete file from disk " + ex.Message, "Shipment Instruction",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
}
NB : the image will be loaded to a flowlayout pannel like this
//Open the files to see
private void ListBoxSourceFiles_Click(object sender, EventArgs e)
{
try
{
if (ListBoxSourceFiles.SelectedItem != null || !ListBoxSourceFiles.SelectedItem.Equals(string.Empty))
{
//MessageBox.Show("Selected " + ListBoxSourceFiles.SelectedItem);
PictureBox pb = new PictureBox();
Image loadedImage = null;
loadedImage = Image.FromFile(ListBoxSourceFiles.SelectedItem.ToString());
pb.Height = loadedImage.Height;
pb.Width = loadedImage.Width;
pb.Image = loadedImage;
flowLayoutPanel1.Controls.Clear();
flowLayoutPanel1.Controls.Add(pb);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Ship Instruction",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
}
You don't say specifically what file you're trying to delete, but from your question it sounds like you're trying to delete the image file that you loaded. If that's the case, then you have a problem. The documentation for Image.FromFile says:
The file remains locked until the Image is disposed.
If you need the ability to delete the file, you'll want to copy the image after you've loaded it, and use that image in your PictureBox. Then you can dispose the loaded image, thereby unlocking the file.
You will not be able to delete any file when is is locked by another process.
You first have to find out which process locks the file.
This is possible with SysInternals ProcessExplorer. Use the "Find handle or DLL" function.
If the file is in use you cannot delete it. However, if you for some reason really want to delete it and you are unable to stop the process that is locking the file (like when uninstalling an application) you can schedule the file for deletion the next time the operating system is restarted. These scheduled deletions are performed before any process is able to lock the file.
You have to use the MoveFileEx Windows API using a null new file name and the flag MOVEFILE_DELAY_UNTIL_REBOOT. How to do that from C# is explained in an answer to the Stack Overflow question “MoveFile” function in C# (Delete file after reboot) C#.
pb.Image.Dispose();
pb.Dispose();
After steps above, tou can use picture again
I've done my reading and understand what a Try/Catch block does and why it's important to use one. But I'm stuck on knowing when/where to use them. Any advice? I'll post a sample of my code below in hopes that someone has some time to make some recommendations for my example.
public AMPFileEntity(string filename)
{
transferFileList tfl = new transferFileList();
_AMPFlag = tfl.isAMPFile(filename);
_requiresPGP = tfl.pgpRequired(filename);
_filename = filename.ToUpper();
_fullSourcePathAndFilename = ConfigurationSettings.AppSettings.Get("sourcePath") + _filename;
_fullDestinationPathAndFilename = ConfigurationSettings.AppSettings.Get("FTPStagePath") + _filename;
_hasBeenPGPdPathAndFilename = ConfigurationSettings.AppSettings.Get("originalsWhichHaveBeenPGPdPath");
}
public int processFile()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine(" ");
sb.AppendLine(" --------------------------------");
sb.AppendLine(" Filename: " + _filename);
sb.AppendLine(" AMPFlag: " + _AMPFlag);
sb.AppendLine(" Requires PGP: " + _requiresPGP);
sb.AppendLine(" --------------------------------");
sb.AppendLine(" ");
string str = sb.ToString();
UtilityLogger.LogToFile(str);
if (_AMPFlag)
{
if (_requiresPGP == true)
{
encryptFile();
}
else
{
UtilityLogger.LogToFile("This file does not require encryption. Moving file to FTPStage directory.");
if (File.Exists(_fullDestinationPathAndFilename))
{
UtilityLogger.LogToFile(_fullDestinationPathAndFilename + " alreadyexists. Archiving that file.");
if (File.Exists(_fullDestinationPathAndFilename + "_archive"))
{
UtilityLogger.LogToFile(_fullDestinationPathAndFilename + "_archive already exists. Overwriting it.");
File.Delete(_fullDestinationPathAndFilename + "_archive");
}
File.Move(_fullDestinationPathAndFilename, _fullDestinationPathAndFilename + "_archive");
}
File.Move(_fullSourcePathAndFilename, _fullDestinationPathAndFilename);
}
}
else
{
UtilityLogger.LogToFile("This file is not an AMP transfer file. Skipping this file.");
}
return (0);
}
private int encryptFile()
{
UtilityLogger.LogToFile("This file requires encryption. Starting encryption process.");
// first check for an existing PGPd file in the destination dir. if exists, archive it - otherwise this one won't save. it doesn't overwrite.
string pgpdFilename = _fullDestinationPathAndFilename + ".PGP";
if(File.Exists(pgpdFilename))
{
UtilityLogger.LogToFile(pgpdFilename + " already exists in the FTPStage directory. Archiving that file." );
if(File.Exists(pgpdFilename + "_archive"))
{
UtilityLogger.LogToFile(pgpdFilename + "_archive already exists. Overwriting it.");
File.Delete(pgpdFilename + "_archive");
}
File.Move(pgpdFilename, pgpdFilename + "_archive");
}
Process pProc = new Process();
pProc.StartInfo.FileName = "pgp.exe";
string strParams = #"--encrypt " + _fullSourcePathAndFilename + " --recipient infinata --output " + _fullDestinationPathAndFilename + ".PGP";
UtilityLogger.LogToFile("Encrypting file. Params: " + strParams);
pProc.StartInfo.Arguments = strParams;
pProc.StartInfo.UseShellExecute = false;
pProc.StartInfo.RedirectStandardOutput = true;
pProc.Start();
pProc.WaitForExit();
//now that it's been PGPd, save the orig in 'hasBeenPGPd' dir
UtilityLogger.LogToFile("PGP encryption complete. Moving original unencrypted file to " + _hasBeenPGPdPathAndFilename);
if(File.Exists(_hasBeenPGPdPathAndFilename + _filename + "original_which_has_been_pgpd"))
{
UtilityLogger.LogToFile(_hasBeenPGPdPathAndFilename + _filename + "original_which_has_been_pgpd already exists. Overwriting it.");
File.Delete(_hasBeenPGPdPathAndFilename + _filename + "original_which_has_been_pgpd");
}
File.Move(_fullSourcePathAndFilename, _hasBeenPGPdPathAndFilename + _filename + "original_which_has_been_pgpd");
return (0);
}
}
}
The basic rule of thumb for catching exceptions is to catch exceptions if and only if you have a meaningful way of handling them.
Don't catch an exception if you're only going to log the exception and throw it up the stack. It serves no meaning and clutters code.
Do catch an exception when you are expecting a failure in a specific part of your code, and if you have a fallback for it.
Of course you always have the case of checked exceptions which require you to use try/catch blocks, in which case you have no other choice. Even with a checked exception, make sure you log properly and handle as cleanly as possible.
Like some others have said, you want to use try-catch blocks around code that can throw an Exception AND code that you are prepared to deal with.
Regarding your particular examples, File.Delete can throw a number of exceptions, for example, IOException, UnauthorizedAccessException. What would you want your application to do in those situations? If you try to delete the file but someone somewhere else is using it, you will get an IOException.
try
{
File.Delete(pgpdFilename + "_archive")
}
catch(IOException)
{
UtilityLogger.LogToFile("File is in use, could not overwrite.");
//do something else meaningful to your application
//perhaps save it under a different name or something
}
Also, keep in mind that if this does fail, then the File.Move you do outside of your if block next will also fail (again to an IOException - since the file was not deleted it is still there which will cause the move to fail).
I was taught to use try/catch/finally for any methods/classes where multiple errors could occur and that you can actually handle. Database transactions, FileSystem I/O, streaming, etc. Core logic usually doesn't require try/catch/finally.
The great part about try/catch/finally is that you can have multiple catches so that you can create a series of exception handlers to deal with very specific error or use a general exception to catch whatever errors you don't see coming.
In your case, you're using File.Exists which is good, but their maybe another problem with the disk that may throw another error that File.Exists cannot handle. Yes, it's a boolean method, but say the File is locked and what happens if you try to write to it? With the catch, you can plan for a rare scenario, but without try/catch/finally, you may be exposing the code to completely unforeseen conditions.
The other guys have given quite a number of good pointers and references.
My input is a short one:
When to use it is one thing, equally or more importanly is how to use it properly.
PS: "it" is refeings to "trying-catching exceptions".