【问题标题】:using FileSystemWatcher to fire event, then delete the newly created file?使用 FileSystemWatcher 触发事件,然后删除新创建的文件?
【发布时间】:2010-09-29 19:49:28
【问题描述】:

我有一个 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查看哪些进程正在锁定文件。

标签: c# windows-services filesystemwatcher


【解决方案1】:

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

【讨论】:

  • 运气不好。同样的错误。 Error: System.IO.IOException: The process cannot access the file 'C:\ProcessBookImages\013Figure.GIF' because it is being used by another process.
  • 我想那一定是观察者本身。我认为 FileSystem 观察者持有对文件的引用,因为 Changed 事件在 Created 事件之前触发。尝试将代码移至 Created 事件。
  • 不,据此 - msdn.microsoft.com/en-us/library/… - 我最后的评论不正确。
  • 啊,明白了(我想)。更改此 Watcher.Created += new FileSystemEventHandler(Watcher_Changed);到这个 Watcher.Changed += new FileSystemEventHandler(Watcher_Changed);
  • 查看我上面的编辑。它与 watcher.changed 无关,它与仍在使用的文件有关。这些文件非常小,因此在将它们添加到目录时只会调用一个事件,那就是 fsw.created。
【解决方案2】:

问题不在于FileSystemWatcher。这是Image.FromFile(FilePath)。该静态方法的行为非常糟糕,并且即使在文件被释放到下一次垃圾回收之前也会在文件上留下锁。在您的打印方法中尝试此操作以获取图像:

Image.FromStream(new MemoryStream(File.ReadAllBytes(FilePath)))

【讨论】:

    【解决方案3】:

    杀死 mydoc,我认为这是保持文件使用的原因

    【讨论】:

      【解决方案4】:

      默认情况下,FSW 在创建文件时触发多个事件,而不仅仅是在文件插入文件系统时触发。为了尽量减少这种影响,我设置了:

      FSW.NotifyFilter  =  NotifyFilters.FileName;
      

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

      如果你用谷歌搜索一下,你会发现很多解决 FSW 限制的解决方案

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多