【问题标题】:Directory scanner Windows Service with FileSystemWatcher带有 FileSystemWatcher 的目录扫描器 Windows 服务
【发布时间】:2011-05-05 10:20:20
【问题描述】:

我正在尝试创建一个 Windows 服务,该服务将抓取上传到目录的新文件,编辑它们并移动到其他目录。看来我可以复制它们但不能移动。这是为什么呢?

using System;
using System.ServiceProcess;
using System.Threading;
using System.IO;

namespace ImportService
{
    public class ImportServer : ServiceBase
    {        
        private System.Diagnostics.EventLog eventLog1;
        private FileSystemWatcher watcher;

        public ImportServer()
        {
            this.ServiceName = "ImportService";

            this.CanHandlePowerEvent = true;
            this.CanHandleSessionChangeEvent = true;
            this.CanPauseAndContinue = true;
            this.CanShutdown = true;
            this.CanStop = true;
            this.AutoLog = true;           

            InitializeComponent();
            if (!System.Diagnostics.EventLog.SourceExists("ImportServiceLogSource"))
                System.Diagnostics.EventLog.CreateEventSource("ImportServiceLogSource", "ImportServiceLog");
            eventLog1.Source = "ImportServiceLogSource";
            eventLog1.Log = "ImportServiceLog";
        }

        public static void Main()
        {
            ServiceBase.Run(new ImportServer());            
        }        

        protected override void OnStart(string[] args)
        {
            //base.OnStart(args);

            eventLog1.WriteEntry("service started");

            watcher = new FileSystemWatcher();
            watcher.Path = "C:\\INPUT\\";
            watcher.Filter = "*.jpg";
            watcher.EnableRaisingEvents = true;
            watcher.Created += new FileSystemEventHandler(OnCreated);            
        }

        private void OnCreated(object sender, FileSystemEventArgs e)
        {
            String output_dir = "C:\\OUTPUT\\";
            String output_file = Path.Combine(output_dir, e.Name);
            File.Move(e.FullPath, output_file);
            // File.Copy() works here
            eventLog1.WriteEntry("moving file to " + output_file);
        }

        protected override void OnStop()
        {            
            eventLog1.WriteEntry("service stopped");
            base.OnStop();
        }

        protected override void OnContinue()
        {
            base.OnContinue();
        }

        protected override void OnPause()
        {
            base.OnPause();
        }

        private void InitializeComponent()
        {
            this.eventLog1 = new System.Diagnostics.EventLog();
            ((System.ComponentModel.ISupportInitialize)(this.eventLog1)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.eventLog1)).EndInit();

        }
    }
}

我还应该保留base.OnStart(); 等。它到底有什么作用?

更新:如何移动在监视目录中创建的文件? 文件已在使用中异常问题。

【问题讨论】:

  • 好的,想出了自动启动的解决方案。 File.Move() 导致问题(服务仅检测到创建/复制的第一个文件,然后崩溃),但仍在处理它。
  • File.Move(...) 抛出什么异常?此外,base.OnStart() 确保 ServiceBase 的 OnStart 方法中的任何内容都能运行。如果什么都没有,则无需调用它。
  • “文件无法移动,因为它被另一个进程使用”。什么样的条件/计时器会尽快移动文件?
  • 想看网络文件夹的文件怎么办??

标签: c# file windows-services filesystemwatcher


【解决方案1】:

您必须捕获 IOException 并使线程休眠一段时间,然后重试。

private void OnCreated(object sender, FileSystemEventArgs e)
{
    String output_dir = "C:\\OUTPUT\\";
    String output_file = Path.Combine(output_dir, e.Name);
    while (true)
    {
        try
        {
            File.Move(e.FullPath, output_file);
            break;
        }
        catch (IOException)
        {
            //sleep for 100 ms
            System.Threading.Thread.Sleep(100);
        }
    }        
    eventLog1.WriteEntry("moving file to " + output_file);
}

话虽如此,这有很多问题。您最好有一个每隔几秒调用一次的计时器事件来查找文件夹中的文件。如果您收到IOException,则继续前进。该文件仍将在下一次迭代中进行处理(假设上传已完成)。如果需要的话,可以给你一个例子。

【讨论】:

  • 谢谢,我在您发布此方法之前尝试过,但问题是这些文件一直在“使用中”。我也试过这个定时器/线程,但我有一些问题让它扫描几次。当我启动服务时,它只处理文件夹中的文件。如果你有一个没有这个问题的例子,我很乐意检查一下。
  • 使用进程资源管理器并找出文件的打开句柄。您可以搜索有问题的文件名。 technet.microsoft.com/en-us/sysinternals/bb896653
  • 好的,现在我已经为每个输入目录创建了线程,但是它们只在我启动服务时扫描目录。这就像 'while(started) { filepaths[] = Directory.GetFiles("C:\");做一点事();线程.睡眠(1000)}'。为什么它只运行一次? :(
  • 它可能会崩溃。将所有这些包装在一个 try/catch 块中。线程可以默默地死掉。另外,显然要确保started是真的。
  • 我不得不使用 DirectoryInfo 和 FileInfo 而不仅仅是 Directory.GetFiles() 在每次迭代时刷新目录内容。谢谢!
【解决方案2】:

如果您要避免服务崩溃,您的OnCreated 实现需要处理异常。处理文件时可能会出现很多问题,并且您的服务需要在它们发生时优雅地恢复。

这里的一种可能性是OnCreated 事件可能会在写入新文件的进程完成写入之前触发,因此您移动文件的尝试会引发异常。

【讨论】:

  • 是的,现在用 try/catch 块解决了这个问题。我得到的例外是“另一个进程使用的文件”。我真的很想在上传完成时强制服务移动文件。本地粘贴到 dir 或通过 ftp 远程上传。
【解决方案3】:

据我了解,您需要等到文件传输完成并关闭文件,然后才能移动文件。

这已经在 SO 上讨论过好几次了。例如。 herehere

【讨论】:

    猜你喜欢
    • 2011-10-14
    • 1970-01-01
    • 1970-01-01
    • 2019-06-03
    • 1970-01-01
    • 1970-01-01
    • 2012-10-03
    • 2010-11-18
    • 2011-06-28
    相关资源
    最近更新 更多