I am monitoroing a folder using FileSystemWatcher and deleting the files created under the folder. But my application is throwing me an exception:
File is being used by another application
ifsXmlFileWatcher.Path = "D:\\";
ifsXmlFileWatcher.IncludeSubdirectories = false;
ifsXmlFileWatcher.EnableRaisingEvents = true;
ifsXmlFileWatcher.Created += new FileSystemEventHandler(IfsFileUpload);
private void IfsFileUpload(object sender, System.IO.FileSystemEventArgs e)
{
try
{
{
File.Delete(e.FullPath);
}
}
catch (Exception exp)
{
MessageBox.Show(exp.Message);
}
}
What might be the problem?
I guess it's a timing problem. The FileSystemWatcher fires it's Created event immediately when the file was created. This does not mean that all content is written to the file and it is closed again. So it's just accessed by the process who created it because this process has not finished writing to it yet.
TO delete it you have to wait until writing has finished.
Problem as you know "File is being used by another application".
So it may be your own application using it or some other application in your environment using it. Possible solution can be
You can keep trying deleting it certain number of times i try here as 5 times and then give up/write event somewhere or show message. I posted similar answer here where someone needs to make sure file copied is success How to know that File.Copy succeeded?
private void IfsFileUpload(object sender, System.IO.FileSystemEventArgs e)
{
bool done = false;
string file = e.FullPath;
int i = 0;
while (i < 5)
{
try
{
System.IO.File.Delete(file);
i = 5;
done = true;
}
catch (Exception exp)
{
System.Diagnostics.Trace.WriteLine("File trouble " + exp.Message);
System.Threading.Thread.Sleep(1000);
i++;
}
}
if (!done)
MessageBox.Show("Failed to delte file " + file);
}
Related
Good day.
In my C# windows forms app, I would like to open .pdf files.
The code to do this is:
private void btnOpenPdf_Click(object sender, EventArgs e)
{
try
{
System.Diagnostics.Process.Start(lblPdf.Text);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
The .pdf file paths are storred in an SQL database.
They are stored in this manner: C:\Folder1\Folder2\File Name
In this example this means:
lblPdf.Text="C:\Folder1\Folder2\File Name";
*note: File Name(s) is/are stored without file type (so no .pdf at the end)
Of course this doesn't work, so I added the "#" and ".pdf" to the string:
lblTest.Text = ("#" + "\"" + lblPdf.Text + ".pdf" + "\"");
When I test this with a Message Box:
MessageBox.Show(lblTest);
I get:
#"C:\Folder1\Folder2\File Name.pdf"
The trouble I am experiencing is that this works:
private void btnOpenPdf_Click(object sender, EventArgs e)
{
try
{
MessageBox.Show(lblTest.Text);
System.Diagnostics.Process.Start(#"C:\Folder1\Folder2\File Name.pdf");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
and this does not work:
private void btnOpenPdf_Click(object sender, EventArgs e)
{
try
{
MessageBox.Show(lblTest.Text);
System.Diagnostics.Process.Start(lblTest.Text);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Can anyone shed a light on why this is so?
The error message I receive in the second example is:
"The system cannot find the file specified"
MessageBox.Show gives me the correct syntax and file path in both cases.
Thank you.
#Shovers and anyone else to whom it may concern:
private void btnOpenPdf_Click(object sender, EventArgs e)
{
lblTest.Text = ("#" +lblPdf.Text + ".pdf" );
try
{
MessageBox.Show(lblTest.Text);
System.Diagnostics.Process.Start(lblTest.Text);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Thanks guys.
Just adding the
+ ".pdf"
to the label (lblPdf.Text) is the answer.
private void btnOpenPdf_Click(object sender, EventArgs e)
{
try
{
System.Diagnostics.Process.Start(lblPdf.Text + ".pdf");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
I can give you a number of hints:
1 Exceptions
Proper exception handling is a pet peeve of mine and yours is problematic. Your code handles fatal exceptions. And never catching fatal exceptions is a very important part. Doing it will only get you more and less understandable followup errors. Here are two artciles on the mater I do link often:
https://blogs.msdn.microsoft.com/ericlippert/2008/09/10/vexing-exceptions/
https://www.codeproject.com/Articles/9538/Exception-Handling-Best-Practices-in-NET
2. How are those PDF stores with the Database?
PDFs are Binary Large Objects (BLOBS). Ther are two schools of tought on to store blobs with a DB and both affect wich path you have to give:
You store the blob itself in the DB. Usually that requires setting up a HTTP handler to provide the file for download/user consumption. In this case you need a URL to access those files
You store the files in the Filesystem. The DB only contains the paths. In this case you have to eitehr use the URL, Share path or whatever else way you got to download those files
SQL Filestream and equivalent attributes from other DB are a bit of a combination of the two. It works mostly like the 1st one, with performance closer to the 2nd one.
You might have some 4th bastardised version here. Or you simply did not understand how how to use the values in the DB.
I've been trying to create an updater app for my .NET application that gets called when an update is detected using a text file that includes the version info. I've created the said updater but it has some problems. When the file is downloaded, it seems like the anti virus software corrupts the file and it can't be opened. Sometimes the updater doesn't run at all and throws an exception ("The underlying connection was closed: The connection was closed unexpectedly.") which seems to also be caused by the local anti virus software. I figured maybe I could download the file in binary format and create the executable locally, but I am not completely sure on how I would do that (or if it would even work). I am still very much a beginner in a lot of areas. So my question is.. how can I efficiently download an update for my application without triggering the anti- virus?
My code:
public Updater()
{
InitializeComponent();
DownloadInfo.RemoteURI = "http://mywebserver.com/Application.exe";
DownloadInfo.NewExecutableName = "update.exe";
DownloadInfo.ExecutableName = "Application.exe";
DownloadInfo.LocDest = AppDomain.CurrentDomain.BaseDirectory;
InvokeUpdate();
}
private void InvokeUpdate()
{
Thread thr = new Thread(() => GetUpdate());
thr.Start();
}
private void GetUpdate()
{
Process[] proc = Process.GetProcessesByName("Application");
if (proc.Length != 0)
proc[0].Kill();
Util.DownloadFile(new Uri(DownloadInfo.RemoteURI), DownloadInfo.LocDest + DownloadInfo.NewExecutableName);
if (File.Exists(DownloadInfo.LocDest + DownloadInfo.ExecutableName))
File.Replace(DownloadInfo.LocDest + DownloadInfo.NewExecutableName, DownloadInfo.LocDest + DownloadInfo.ExecutableName, DownloadInfo.LocDest + "backup.exe");
else
File.Move(DownloadInfo.LocDest + DownloadInfo.NewExecutableName, DownloadInfo.LocDest + DownloadInfo.ExecutableName);
try
{
File.Delete(DownloadInfo.LocDest + "backup.exe");
}
catch { }
try
{
Process.Start(DownloadInfo.LocDest + DownloadInfo.ExecutableName);
}
catch { };
Invoke((MethodInvoker)(() => this.Close()));
}
And my DownloadFile method from my util class..
public static void DownloadFile(Uri remoteURI, string localDest)
{
try
{
using (WebClient webclient = new WebClient())
{
webclient.DownloadFile(remoteURI, localDest);
}
}
catch { }
}
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