C# FileSystemWatcher在保存文件之前激发-如何;暂停“;过程是什么?

C# FileSystemWatcher在保存文件之前激发-如何;暂停“;过程是什么?,c#,multithreading,io,C#,Multithreading,Io,下面是我正在尝试的逻辑代码: 服务监视目录中的.pptx文件。 如果文件已更改,请执行到jpg的转换。然后执行其他任务,这些任务将在以后添加 我使用的是file wather对象,但它会在我打开文件时立即触发,因此我想通过检查文件是否“锁定”来停止进程。我认为“whilelocked”循环可以解决这个问题,但不是。下面是简化的代码原型,我想知道您是否可以看看它,看看我做错了什么,以及/或者是否有更好的方法为生产环境编写这篇文章。pptx文件可以长时间打开 namespace FileWatche

下面是我正在尝试的逻辑代码:

服务监视目录中的.pptx文件。 如果文件已更改,请执行到jpg的转换。然后执行其他任务,这些任务将在以后添加

我使用的是file wather对象,但它会在我打开文件时立即触发,因此我想通过检查文件是否“锁定”来停止进程。我认为“whilelocked”循环可以解决这个问题,但不是。下面是简化的代码原型,我想知道您是否可以看看它,看看我做错了什么,以及/或者是否有更好的方法为生产环境编写这篇文章。pptx文件可以长时间打开

namespace FileWatcherDemo
{
   public class Program
   {

    static void Main(string[] args)
    {
        FileSystemWatcher fsWatcher = new FileSystemWatcher();
        fsWatcher.Path = @"e:\\";

        fsWatcher.NotifyFilter = NotifyFilters.LastWrite; 

        fsWatcher.Filter = "*.pptx";
        fsWatcher.Changed += new FileSystemEventHandler(fsWatcher_Changed);
        //fsWatcher.Created += new FileSystemEventHandler(fsWatcher_Changed);
        //fsWatcher.Deleted += new FileSystemEventHandler(fsWatcher_Changed);
        //fsWatcher.Renamed += new RenamedEventHandler(fsWatcher_Changed);
        fsWatcher.EnableRaisingEvents = true;
        Console.ReadKey();
    }        

    static void fsWatcher_Changed(object sender, FileSystemEventArgs e)
    {
        try
        {
            while( !IsFileLocked())
            {
                Console.WriteLine("Changed Event Fired");
                Microsoft.Office.Interop.PowerPoint.Application app = new Microsoft.Office.Interop.PowerPoint.Application();
                Presentation pptPresentation = app.Presentations.Open(@"e:\\HowTo.pptx", MsoTriState.msoFalse, MsoTriState.msoFalse, MsoTriState.msoFalse);

                pptPresentation.SaveAs(@"e:\\Output", PpSaveAsFileType.ppSaveAsJPG, MsoTriState.msoFalse);
                pptPresentation.Close();
            }
        }
        catch (Exception ex)
        {
            using (StreamWriter w = File.AppendText(@"e:\\ErrorLog.txt"))
            {
                Log(ex.Message.ToString(), w);
                Log(ex.StackTrace.ToString(), w);

                w.Close();
            }
        }

        Console.ReadKey();
    }

    static bool IsFileLocked()
    {
        FileStream fs = null;
        FileInfo file = new FileInfo(@"e:\\HowTo.pptx");            

        try
        {
            fs = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
        }
        catch (IOException)
        {
            return true;
        }
        finally
        {
            if(fs != null)
                fs.Close();
        }
        return false;
    }

    public static void Log(string LogMessage, TextWriter w)
    {
        w.Write("\r\nLog Entry: ");
        w.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(), DateTime.Now.ToLongDateString());
        w.WriteLine("  :");
        w.WriteLine("  {0}", LogMessage.ToString());
        w.WriteLine("------------------------------------------");

        w.Flush();
    }
}

}还有一个想法:当FileSystemWatcher检测到更改时(您说它会在文件打开后立即触发),记录文件的LastModifiedTime并保持循环,直到文件的LastModifiedTime更改为止(假设LastModifiedTime仅在文件保存时写入-我不知道实际何时完成)然后执行转换为JPG的过程

编辑

添加应演示如何跟踪文件修改时间的代码:

class Program
{
    static void Main(string[] args)
    {
        Thread t = new Thread(()=> DoTest());
        t.Start();

        Console.WriteLine("Waiting...");
        Console.ReadKey();
    }

    private static void DoTest()
    {
        FileSystemWatcher fsw = new FileSystemWatcher("C:\\");
        fsw.Filter = "*.txt";
        fsw.Changed += new FileSystemEventHandler(fsw_Changed);
        fsw.Deleted += new FileSystemEventHandler(fsw_Deleted);
        fsw.Renamed += new RenamedEventHandler(fsw_Renamed);
        fsw.Created += new FileSystemEventHandler(fsw_Created);
        fsw.EnableRaisingEvents = true;
    }

    static void fsw_Created(object sender, FileSystemEventArgs e)
    {
        FileInfo fi = new FileInfo(e.FullPath);
        Console.WriteLine("File Created: "+e.FullPath);
        Console.WriteLine("Creation Time: " + fi.CreationTime.ToLongTimeString());
        Console.WriteLine("Last Access Time: " + fi.LastAccessTime.ToLongTimeString());
        Console.WriteLine("Last Write Time: " + fi.LastWriteTime.ToLongTimeString());
        Console.WriteLine("Length: " + fi.Length);

    }

    static void fsw_Renamed(object sender, RenamedEventArgs e)
    {
        FileInfo fi = new FileInfo(e.FullPath);
        Console.WriteLine("File Renamed: "+e.FullPath);
        Console.WriteLine("Creation Time: " + fi.CreationTime.ToLongTimeString());
        Console.WriteLine("Access Time: " + fi.LastAccessTime.ToLongTimeString());
        Console.WriteLine("Last Write Time: " + fi.LastWriteTime.ToLongTimeString());
        Console.WriteLine("Length: " + fi.Length);
    }

    static void fsw_Deleted(object sender, FileSystemEventArgs e)
    {
        FileInfo fi = new FileInfo(e.FullPath);
        Console.WriteLine("File Deleted: "+e.FullPath);
        Console.WriteLine("Creation Time: " + fi.CreationTime.ToLongTimeString());
        Console.WriteLine("Last Access Time: " + fi.LastAccessTime.ToLongTimeString());
        Console.WriteLine("Last Write Time: " + fi.LastWriteTime.ToLongTimeString());

    }

    static void fsw_Changed(object sender, FileSystemEventArgs e)
    {
        FileInfo fi = new FileInfo(e.FullPath);
        Console.WriteLine("File Changed: "+e.FullPath);
        Console.WriteLine("Creation Time: " + fi.CreationTime.ToLongTimeString());
        Console.WriteLine("Last Access Time: " + fi.LastAccessTime.ToLongTimeString());
        Console.WriteLine("Last Write Time: " + fi.LastWriteTime.ToLongTimeString());
        Console.WriteLine("Length: " + fi.Length);
    }
}

要使FileSystemWatcher适合于生产级代码,需要执行大量逻辑

  • 您希望事件处理程序非常简单,只需将发生的事件排队,然后稍后再处理

  • 使用计时器(最好是System.Threading)以1000毫秒的延迟处理队列,当您收到事件时,停止/启动计时器

  • 检查队列中同一文件的多个事件,例如,一个程序可能创建一个文件,然后再次删除它

编辑:我刚刚在谷歌上快速搜索了一下,找到了一篇文章和示例代码,可以让你达到90%的目标

编辑2:请重新阅读您的问题。上述建议仍然适用,但是您还需要做一些事情来解决您的问题:

  • Powerpoint与其他Office应用程序一样,创建一个带有
    ~
    前缀的隐藏临时文件

  • 检查文件修改时间戳。当您第一次注意到文件已更改时,请保存修改时间,并在下次更改文件时与之进行比较

  • 您需要设置文件系统监视程序的某个标志属性以获得修改时间更改


希望所有这些都有帮助

是的,FileInfo的LastAccesTime确实显示了时间,而不是当前时间,这正是我想要的。但是,没有跟踪更改的属性。你如何测试它?谢谢。@Risho我不知道你为什么说没有跟踪变化的属性。我正在用示例代码编辑我的答案。我能够监视文件上的更改事件,并且每次修改文件时,时间确实会增加。因为所有fsw方法都是在我单击文件时触发的,而不是在保存文件时触发的。我必须解释文件可能会打开几个小时。@Risho:那不是真的。实际保存文件时,将触发更改的事件。我自己测试了100次。也许您的代码还有其他问题?我感谢您的时间和努力,因为完成这项工作至关重要。但事实并非如此。现在这只是一个控制台应用程序,只要我运行它并打开文件,就会立即触发FileSystemWather更改事件。如果我没有在方法内部设置断点,程序将在修改我的文件之前运行该方法。@SuperJMN,谢谢您的报告。我已经用档案中的副本修复了链接。