如何确定文件夹是否已完成复制c#

时间:2013-07-12 18:35:49

标签: c# .net directory filesystemwatcher

我有一个问题:如何确定文件夹是否已从一个位置复制到另一个位置?

目前,我的FileSystemWatcher会在复制目录中的文件后立即触发多个事件。我想要的是,当成功复制该文件夹中的所有文件时,将触发一个单独的事件。我的代码现在看起来像这样:

static void Main(string[] args)
    {
        String path = @"D:\Music";
        FileSystemWatcher mWatcher = new FileSystemWatcher();
        mWatcher.Path = path;
        mWatcher.NotifyFilter = NotifyFilters.LastAccess;
        mWatcher.NotifyFilter = mWatcher.NotifyFilter | NotifyFilters.LastWrite;
        mWatcher.NotifyFilter = mWatcher.NotifyFilter | NotifyFilters.DirectoryName;
        mWatcher.IncludeSubdirectories = true;
        mWatcher.Created += new FileSystemEventHandler(mLastChange);
        mWatcher.Changed += new FileSystemEventHandler(mLastChange);

        mWatcher.EnableRaisingEvents = true;
        Console.WriteLine("Watching path: " + path);



        String exit;
        while (true)
        {
               exit = Console.ReadLine();
               if (exit == "exit")
                   break;

        }


    }



    private static void mLastChange(Object sender, FileSystemEventArgs e)
    {
        Console.WriteLine(e.ChangeType + " " + e.FullPath);
    }

5 个答案:

答案 0 :(得分:2)

不幸的是,FileSystemWatcher没有告诉你文件写完的时间。所以你的选择是......

  1. 假设没有更多更改
  2. ,在上次写入后设置超时
  3. 让写作应用程序放置一个多种类型的锁定文件,告诉任何其他程序它已完成。
  4. 重新阅读你的问题后......听起来你对其他应用程序没有任何控制权。

    因此,您需要某种超时值来确定何时完成所有写入操作。基本上创建一个在每个filesystemwatcher事件之后重置的计时器......当它超时时,你会触发表明它完成的单个事件。

    以下是将其添加到代码中的方法......

    static void Main(string[] args)
    {
        Timer.Interval = 5000; // 5 seconds - change to whatever is appropriate
        Timer.AutoReset = false;
        Timer.Elapsed += TimeoutDone;
        String path = @"D:\Music";
        FileSystemWatcher mWatcher = new FileSystemWatcher();
        mWatcher.Path = path;
        mWatcher.NotifyFilter = NotifyFilters.LastAccess;
        mWatcher.NotifyFilter = mWatcher.NotifyFilter | NotifyFilters.LastWrite;
        mWatcher.NotifyFilter = mWatcher.NotifyFilter | NotifyFilters.DirectoryName;
        mWatcher.IncludeSubdirectories = true;
        mWatcher.Created += new FileSystemEventHandler(mLastChange);
        mWatcher.Changed += new FileSystemEventHandler(mLastChange);
    
        mWatcher.EnableRaisingEvents = true;
        Console.WriteLine("Watching path: " + path);
        Timer.Start();
    
        String exit;
        while (true)
        {
            exit = Console.ReadLine();
            if (exit == "exit")
                break;
    
        }
    }
    
    private static Timer Timer = new Timer();
    
    private static void TimeoutDone(object source, ElapsedEventArgs e)
    {
        Console.WriteLine("Timer elapsed!");
    }
    
    private static void mLastChange(Object sender, FileSystemEventArgs e)
    {
        Console.WriteLine(e.ChangeType + " " + e.FullPath);
        if (Timer != null)
        {
            Timer.Stop();
            Timer.Start();
        }
    }
    

答案 1 :(得分:0)

它非常俗气,但过去我通过为FileSystemWatcher类创建自定义装饰器来处理这个问题。在内部,它创建一个FileSystemWatcher并注册Created和Changed事件,包装它们,并在文件完成后抛出自己的Created和Changed事件,类似于:

private void Watcher_Changed(Object sender, FileSystemEVentArgs e)
    {
        while (true)
        {
            FileStream stream;
            try
            {
                stream = File.Open(e.FullPath, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
                // If this succeeds, the file is finished
                Changed();
            }
            catch (IOException)
            {
            }
            finally
            {
                if (stream != null) stream.Close();
            }
        }
    }

其中一部分来自答案here。实际上,您不应该使用无限循环。你可能想要增加超时,在支票之间睡觉等等,但这是一般的想法。

答案 2 :(得分:0)

如果目标是本地文件夹,则可以使用文件系统筛选器驱动程序来跟踪文件创建文件关闭事件。知道以前创建的所有文件何时关闭将通知您复制已完成。

答案 3 :(得分:0)

我创建了一个带有扩展FileSystemWatcher的类的Git仓库,只有在复制完成后才会触发事件。

下载FileSystemSafeWatcher并将其添加到您的项目中。

然后将其用作普通FileSystemWatcher并监控事件的触发时间。

var fsw = new FileExamSystemWatcher(file);
fsw.EnableRaisingEvents = true;
// Add event handlers here
fsw.Created += fsw_Created;

答案 4 :(得分:0)

不幸的是,没有现成的解决方案。但是我设计了一个简单的棘手解决方案来触发(复制完成)事件。

您应该使用计时器。

#Software: Microsoft Internet Information Services 10.0
#Version: 1.0
#Date: 2019-08-22 08:17:09
#Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) cs(Referer) sc-status sc-substatus sc-win32-status time-taken
2019-08-22 08:17:09 127.0.0.1 Delete /v1/client/webhook - 80 - 127.0.0.1 - - 404 4 2 3