使用FileSystemWatcher触发事件后,如何删除新创建的文件?

3
我有一个Windows服务,使用FileSystemWatcher监视文件夹,打印添加的图像,然后在打印后删除该图像。
 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());
                }
            }
        }

问题在于,当我尝试删除文件时,会抛出异常:Error: System.IO.IOException: The process cannot access the file because it is being used by another process. 我猜测是因为FileSystemWatcher正在保持对该文件的某种引用。你有什么办法,在文件打印后删除该文件吗? 编辑: 之前没有包含我的代码中的这个函数:
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;
            }
        }

我也将using块建议应用到了这个函数中,并将删除操作移动到了这个函数中,这个函数是mydoc.EndPrint的事件处理程序,以确保与文件的所有联系都被断开,这似乎解决了问题。

void myDoc_EndPrint(object sender, PrintEventArgs e)
{
    File.Delete(FilePath);
}

使用 FileMon 查看哪些进程正在锁定该文件。 - Oded
4个回答

2

PrintDocument实现了IDisposable接口,你需要使用using块来确保它释放文件句柄。

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());
        }
    }
}

没有运气。同样的错误。错误:System.IO.IOException:由于正在被另一个进程使用,因此无法访问文件'C:\ProcessBookImages\013Figure.GIF'。 - xdumaine
我猜应该是监视器本身的问题。我认为FileSystem监视器正在保留对文件的引用,因为Changed事件在Created事件之前触发。尝试将代码移动到Created事件中。 - Christopher Edwards
不,根据这个链接 - http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.created.aspx - 我上次的评论是不正确的。 - Christopher Edwards
好的,我明白了(我想)。将这个 Watcher.Created += new FileSystemEventHandler(Watcher_Changed); 改为 Watcher.Changed += new FileSystemEventHandler(Watcher_Changed);。 - Christopher Edwards
如果这不起作用,删除File.Delete(e.FullPath);这一行,并确保事件没有多次触发。 - Christopher Edwards
1
请查看我的编辑。这与watcher.changed无关,而是文件仍在使用。这些文件非常小,因此当它们添加到目录中时,只会调用一个事件,即fsw.created。 - xdumaine

1
问题不在于 FileSystemWatcher,而是在于 Image.FromFile(FilePath)。这个静态方法的行为非常糟糕,即使在释放后仍会对文件进行锁定,直到下一次垃圾回收。在您的打印方法中尝试使用以下代码来获取图像:
Image.FromStream(new MemoryStream(File.ReadAllBytes(FilePath)))

0

默认情况下,FSW在文件创建过程中会触发多个事件,而不仅仅是在文件插入文件系统时触发。为了最小化这种影响,我设置了:

FSW.NotifyFilter  =  NotifyFilters.FileName;

当文件首次创建而不是完全加载到文件系统时,FSW也会触发此事件。如果您有一个大文件,那么在此事件触发和文件实际可用之间将存在明显的时间延迟。没有FSW事件告诉您文件何时完全写入。为了解决这个问题,我使用重试循环来以独占方式打开文件,并使用try/catch捕获错误。并且在失败时继续尝试加载文件,直到成功(或达到重试限制),并在失败时休眠一段时间。

如果您在谷歌上搜索一下,就会找到许多解决FSW限制的方法。


0

删除 mydoc,我认为这是导致文件被占用的原因。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接