Reputation: 10329
I have a windows service using a FileSystemWatcher to monitor a folder, print added images, then delete the image after printing.
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
FileSystemWatcher Watcher = new FileSystemWatcher();
Watcher.Path = @"C:\Images";
Watcher.Created += new FileSystemEventHandler(Watcher_Changed);
Watcher.EnableRaisingEvents = true;
}
private void Watcher_Changed(object sender, FileSystemEventArgs e)
{
try
{
PrintDocument myDoc = new PrintDocument();
myDoc.PrintPage += new PrintPageEventHandler(print);
FilePath = e.FullPath;
myDoc.PrinterSettings.PrinterName = @"\\Network Printer";
myDoc.Print();
using (StreamWriter sw = new StreamWriter("C:\\error.txt"))
{
sw.WriteLine("Printed File: " + FilePath);
}
File.Delete(e.FullPath);
}
catch(Exception excep)
{
using (StreamWriter sw = new StreamWriter("C:\\error.txt"))
{
sw.WriteLine("Error: " + excep.ToString());
}
}
}
The problem is that I get the exception thrown Error: System.IO.IOException: The process cannot access the file because it is being used by another process.
that the file is being used by another process when I try to delete it. I'm guessing this is because the FileSystemWatcher is keeping some sort of reference to it. Any idea on what to do here, to delete the file after it gets printed?
Edit: Did not include this function from my code before:
private void print(object sender, PrintPageEventArgs e)
{
try
{
using (Image i = Image.FromFile(FilePath))
{
Point p = new Point(0, 0);
e.Graphics.DrawImage(i, p);
}
}
catch(Exception exep)
{
throw exep;
}
}
I applied the using block suggestion to this function too, but also moved the delete to this function which is event handler for mydoc.EndPrint, to ensure all ties to the file were cut, and this seems to do the trick.
void myDoc_EndPrint(object sender, PrintEventArgs e)
{
File.Delete(FilePath);
}
Upvotes: 3
Views: 5604
Reputation: 11
The problem is not with the FileSystemWatcher
. It's with Image.FromFile(FilePath)
. That static method behaves very poorly and leaves a lock on the file even after it is disposed until the next garbage collection. Try this in your print method to get the image:
Image.FromStream(new MemoryStream(File.ReadAllBytes(FilePath)))
Upvotes: 1
Reputation: 7493
By default the FSW fires multiple events while the file is being created, not just for when the file is inserted into the filesystem. To minimize this effect I set:
FSW.NotifyFilter = NotifyFilters.FileName;
Also the FSW fires this event when the file is first created and not when it has completely loaded into the filesystem. If you have a large file then there will be a distinct time delay between this event firing and the file actually being available for use. There is no FSW even that tells you when the file has been completely written. To get around this I use a retry loop to open the file for exclusive reading and trap errors with a try/catch. And keep trying to load the file until I succeed (or I hit a retry limit) and sleeping for a bit when I fail.
If you google around a bit you will find lots of solutions for getting around FSW limitations
Upvotes: 0
Reputation: 6659
PrintDocument implements IDisposable, you need to make sure it releases it's file handle by wrapping it in a using block.
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
FileSystemWatcher Watcher = new FileSystemWatcher();
Watcher.Path = @"C:\Images";
Watcher.Created += new FileSystemEventHandler(Watcher_Changed);
Watcher.EnableRaisingEvents = true;
}
private void Watcher_Changed(object sender, FileSystemEventArgs e)
{
try
{
using (PrintDocument myDoc = new PrintDocument())
{
myDoc.PrintPage += new PrintPageEventHandler(print);
FilePath = e.FullPath;
myDoc.PrinterSettings.PrinterName = @"\\Network Printer";
myDoc.Print();
using (StreamWriter sw = new StreamWriter("C:\\error.txt"))
{
sw.WriteLine("Printed File: " + FilePath);
}
}
File.Delete(e.FullPath);
}
catch(Exception excep)
{
using (StreamWriter sw = new StreamWriter("C:\\error.txt"))
{
sw.WriteLine("Error: " + excep.ToString());
}
}
}
Upvotes: 2