Сканер каталогов Служба Windows с FileSystemWatcher

Я пытаюсь создать службу 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(); и т. д. Что это действительно делает?

ОБНОВЛЕНИЕ: как переместить файл, созданный в отслеживаемой директории? Проблема исключения Файл уже используется.


person yosh    schedule 05.05.2011    source источник
comment
Хорошо, разобрался с автозапуском. File.Move() вызывает проблему (служба обнаруживает только 1-й файл, созданный/скопированный, а затем аварийно завершает работу), но все еще работает над ним.   -  person yosh    schedule 05.05.2011
comment
Какое исключение выдает File.Move(...)? Кроме того, base.OnStart() гарантирует, что все в методе OnStart ServiceBase запустится. Если ничего нет, то и звонить не нужно.   -  person Russ Clarke    schedule 05.05.2011
comment
Файл нельзя переместить, так как он используется другим процессом. Какое условие/таймер переместит файл как можно скорее?   -  person yosh    schedule 05.05.2011
comment
Что делать, если я хочу посмотреть файлы сетевой папки??   -  person Rohit Vyas    schedule 16.04.2013


Ответы (3)


Вам придется поймать 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, вы просто идете дальше. Файл все еще будет доступен для обработки на следующей итерации (при условии, что загрузка завершена). Могу привести пример, если то, о чем я говорю, если нужно.

person Tim Coker    schedule 05.05.2011
comment
Спасибо, я пробовал до того, как вы опубликовали этот подход, но проблема в том, что эти файлы используются все время. Я также пробовал этот таймер / многопоточность, но у меня возникла проблема, чтобы заставить его сканировать несколько раз. Пока я запускаю службу, я работал только с файлами в папке. Если у вас есть пример без этой проблемы, я бы хотел его проверить. - person yosh; 05.05.2011
comment
Используйте проводник процессов и выясните, что имеет открытый дескриптор файлов. Вы можете выполнить поиск по имени файла, о котором идет речь. technet.microsoft.com/en-us/sysinternals/bb896653 - person Tim Coker; 05.05.2011
comment
Итак, теперь я создал потоки для каждого входного каталога, однако они сканируют каталоги только при запуске службы. Это похоже на «пока (начато) { пути к файлам [] = Directory.GetFiles (C: \); сделай что-нибудь(); Thread.Sleep(1000) }'. Почему он запускается только один раз? :( - person yosh; 05.05.2011
comment
Это может быть сбой. Оберните все это в блоке try/catch. Потоки могут тихо умереть. Кроме того, убедитесь, что start имеет значение true, очевидно. - person Tim Coker; 05.05.2011
comment
Мне пришлось использовать DirectoryInfo и FileInfo вместо просто Directory.GetFiles() для обновления содержимого каталога при каждой итерации. Спасибо! - person yosh; 06.05.2011

Ваша реализация OnCreated должна обрабатывать исключения, если вы хотите избежать сбоя службы. Многое может пойти не так при обработке файла, и ваша служба должна корректно восстанавливаться, когда это происходит.

Одна из возможностей здесь заключается в том, что событие OnCreated может сработать до того, как процесс, записывающий новый файл, завершит его запись, и поэтому ваша попытка переместить файл вызовет исключение.

person Chris Dickson    schedule 05.05.2011
comment
Да, на данный момент это исправлено блоком try/catch. Исключением, которое я получаю, является файл, используемый другим процессом. Я действительно хотел бы заставить службу перемещать файл после завершения загрузки. Либо вставить локально в каталог, либо загрузить удаленно через ftp. - person yosh; 05.05.2011

Как я понимаю, нужно дождаться завершения передачи файла и закрытия файла, и только после этого можно перемещать файл.

Это обсуждалось ранее на SO несколько раз. Например. здесь и здесь.

person Eugene Mayevski 'Callback    schedule 05.05.2011