2

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.

yosh
  • 3,245
  • 7
  • 55
  • 84
  • Ok, figured out the auto-start solution. The File.Move() is causing a problem (service detects only 1st file created/copied and then crashes), but still working on it. – yosh May 05 '11 at 11:01
  • What exception is File.Move(...) throwing ? Also, base.OnStart() ensures that anything in ServiceBase's OnStart method gets run. If there's nothing, you don't need to call it. – Russ Clarke May 05 '11 at 11:31
  • "File cannot be moved because it's used by another process". What kind of condition/timer would move the file ASAP ? – yosh May 05 '11 at 11:50
  • What if I want to watch the files of network folder?? – Rohit Vyas Apr 16 '13 at 14:33

3 Answers3

2

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.

Tim Coker
  • 6,484
  • 2
  • 31
  • 62
  • Thanks, I tried before this approach you posted but the problem is these files are all the time "in use". I've also tried this timer/threading but I had some problem there to make it scan several times. It was only working with files in folder while I start the service. If you have an example without this problem I'd love to check it. – yosh May 05 '11 at 12:51
  • Use process explorer and figure out what has an open handle to the files. You can do a search for the file name in question. http://technet.microsoft.com/en-us/sysinternals/bb896653 – Tim Coker May 05 '11 at 13:06
  • Ok, so now I've created threads for each input directory however they only scan dirs when I start the service. It's like 'while(started) { filepaths[] = Directory.GetFiles("C:\"); doSomething(); Thread.Sleep(1000) }'. Why does it run only once? :( – yosh May 05 '11 at 14:38
  • It might be crashing. Wrap all of it in a try/catch block. Threads can silently die. Also, make sure started is true, obviously. – Tim Coker May 05 '11 at 18:33
  • I had to use DirectoryInfo and FileInfo instead of just Directory.GetFiles() to refresh dir content with every iteration. Thanks! – yosh May 06 '11 at 08:09
0

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.

Chris Dickson
  • 11,964
  • 1
  • 39
  • 60
  • Yeah, fixed that for now with try/catch block. The exception I get is "file used by another process". I would really like to force service to move the file whenever the upload is complete. Either pasted locally to dir or uploaded remotely via ftp. – yosh May 05 '11 at 11:52
0

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.

Community
  • 1
  • 1
Eugene Mayevski 'Callback
  • 45,135
  • 8
  • 71
  • 121