2011-05-05 124 views
2

我试图创建一个Windows服务,将抓住新文件上传到目录,编辑它们并移动到其他目录。看来我可以复制它们,但不能移动。这是为什么?目录扫描仪Windows服务与FileSystemWatcher

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();等。它真的做什么?

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

+0

好的,找出了自动启动解决方案。 File.Move()导致一个问题(服务仅检测到第一个创建/复制的文件,然后崩溃),但仍在处理它。 – yosh 2011-05-05 11:01:46

+0

File.Move(...)抛出什么异常?此外,base.OnStart()可确保运行ServiceBase的OnStart方法中的任何内容。如果没有什么,你不需要叫它。 – 2011-05-05 11:31:15

+0

“文件无法移动,因为它被另一个进程使用”。什么样的条件/计时器会尽快移动文件? – yosh 2011-05-05 11:50:52

回答

2

您将不得不赶上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,你就继续前进。该文件仍然会在下一次迭代中进行处理(假设上传已完成)。如果我需要的话可以给我一个例子。

+0

谢谢,我之前尝试过这种方法,但问题是这些文件一直在“使用中”。我也试过这个定时器/线程,但是我有一些问题让它扫描几次。当我启动服务时,它只处理文件夹中的文件。如果你有一个没有这个问题的例子,我很想去检查它。 – yosh 2011-05-05 12:51:16

+0

使用进程资源管理器并找出哪些文件具有打开的句柄。您可以搜索相关文件名称。 http://technet.microsoft.com/en-us/sysinternals/bb896653 – 2011-05-05 13:06:57

+0

好吧,现在我已经为每个输入目录创建了线程,但是他们只在我启动服务时扫描目录。这就像'while(started){filepaths [] = Directory.GetFiles(“C:\”);做一点事(); Thread.Sleep(1000)}'。它为什么只运行一次? :( – yosh 2011-05-05 14:38:48

0

如果您要避免服务崩溃,则您的OnCreated实施需要处理异常。处理文件时可能会出现很多问题,并且您的服务需要在执行时恢复正常。

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

+0

是的,现在用try/catch块来解决这个问题。我得到的例外是“另一个进程使用的文件”。只要上传完成,我真的很想强制服务来移动文件。既可以本地粘贴到目录,也可以通过ftp远程上传。 – yosh 2011-05-05 11:52:00

0

据我所知,您需要等到文件传输完成并且文件关闭后才能移动文件。

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