Directory scanner Windows Service with FileSystemWatcher
I'm trying to create a windows service that will grab new files uploaded to directory, edit them and move to other directory. It seems I can COPY them but not MOVE. Why is that?
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();
}
}
}
Also should I keep the base.OnStart();
etc. What does it really do?
UPDATE: How to move file that was created in the watched directory? File already in use exception problem.
You'll have to catch the IOException and make the thread sleep for a few bit then try again.
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);
}
That being said, there are a ton of problems with this. You're going to be better off having a timer event that gets called every few seconds that looks for files in the folder. If you get an IOException
, you just move on. The file will still be there for processing on th next iteration (assuming the upload has finished). Can give you an example if what I'm talking about if needed.
Your implementation of OnCreated
needs to handle exceptions if you are to avoid the service crashing. Lots of things might go wrong when handling the file, and your service needs to recover gracefully when they do.
One possibility here is that the OnCreated
event may fire before the process writing the new file has finished writing it, and your attempt to move the file is therefore throwing an exception.
As I understand, you need to wait until the file transfer is complete and the file is closed, and only then you can move the file.
This has been discussed before on SO several times. Eg. here and here.
精彩评论