Search code examples
c#filewindows-servicesfilesystemwatcher

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.


Solution

  • 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.