简体   繁体   English

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

[英]How to determine whether a folder has finished copying c#

I have a question: How do I determine whether a folder has finished copying from one location to another? 我有一个问题:如何确定文件夹是否已完成从一个位置到另一个位置的复制?

At the moment my FileSystemWatcher triggers several events as soon as a file within the directory being copied. 目前,一旦复制目录中的文件,我的FileSystemWatcher就会触发多个事件。 What I want though, is one single event to be triggered when all the files within that folder has been successfully copied. 我想要的是,成功复制该文件夹中的所有文件后将触发一个事件。 My code right now looks like this: 我的代码现在看起来像这样:

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);
    }

Unfortunately FileSystemWatcher doesn't tell you when a file is finished writing. 不幸的是,FileSystemWatcher不会告诉您文件何时完成写入。 So your options are... 所以你的选择是...

  1. Set a timeout after last write when it is assumed there are no more changes coming 假设没有更多更改来临,请在最后一次写入后设置超时
  2. Have the writing application put a lock file of some variety that tells any other program that it's done. 让编写应用程序放置一个各种各样的锁文件,以告诉其他程序它已完成。

After re-reading your question... it doesn't sound like you have any control over the other application. 重新阅读您的问题后,听起来您对其他应用程序没有任何控制权。

So you will need some kind of timeout value that determines when all the writing is done. 因此,您将需要某种超时值来确定何时完成所有写入。 Basically create a timer that resets after each filesystemwatcher event... when it times out then you fire the single event that says it's done. 基本上创建一个计时器,该计时器在每个filesystemwatcher事件发生后重置...当它超时时,您将触发一个表明已完成的事件。

Here is how you could add it to your code... 这是将其添加到代码中的方法...

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();
    }
}

It's horribly cheesy, but in the past I have dealt with this problem by creating a custom decorator for the FileSystemWatcher class. 太俗气了,但过去我通过为FileSystemWatcher类创建自定义装饰器来解决此问题。 Internally it creates a FileSystemWatcher and registers for the Created and Changed events, wraps them, and throws its own Created and Changed events after the files are finished, similar to this: 在内部,它创建一个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();
            }
        }
    }

Some of this is drawn from the answer here . 其中一些是从这里的答案中得出的。 In reality, you shouldn't use an infinite loop. 实际上,您不应该使用无限循环。 You probably want to add timeouts, sleep in between checks, etc. but this is the general idea. 您可能想要添加超时,在两次检查之间睡眠,等等,但这是一般的想法。

If the destination is a local folder, you can use the filesystem filter driver to track file create and file close events. 如果目标是本地文件夹,则可以使用文件系统过滤器驱动程序来跟踪文件创建文件关闭事件。 Knowing when all files, previously created, are closed will inform you that copying is complete. 知道所有先前创建的文件何时关闭将通知您复制已完成。

I have created a Git repo with a class that extends FileSystemWatcher to trigger the events only when copy is done. 我用一个扩展FileSystemWatcher的类创建了一个Git存储库,使其仅在复制完成后才触发事件。

Download FileSystemSafeWatcher and add it to your project. 下载FileSystemSafeWatcher并将其添加到您的项目中。

Then use it as a normal FileSystemWatcher and monitor when the events are triggered. 然后将其用作普通的FileSystemWatcher并监视何时触发事件。

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

Unfortunatly there is no ready solution. 不幸的是,还没有现成的解决方案。 but I designed a simple tricky solution to trigger (copy finished) event. 但是我设计了一个简单的棘手解决方案来触发(复制完成)事件。

you should use timer. 您应该使用计时器。

        FileSystemWatcher fsw = new FileSystemWatcher();
        string fullPath = "";
        DateTime tempTime;
        fsw.Path = @"C:\temp";

        private void startwatching()
        {
            timer1.Start();
        }
        fsw.EnableRaisingEvents = true;
        fsw.Created += Fsw_Created;

        private void Fsw_Created(object sender, FileSystemEventArgs e)
        {
            tempTime = DateTime.Now.AddSeconds(-4);
            fullPath = e.FullPath;
        }

    private void timer1_Tick(object sender, EventArgs e)
    {
        if (fullPath!=string.Empty)
        {
            timer1.Stop();
            if (tempTime >= Directory.GetLastAccessTime(fullPath))
            {
                DirectoryInfo di = new DirectoryInfo(fullPath);
                listBox1.Items.Add("Folder " + di.Name + " finished copying");
                fullPath = string.Empty;
            }
            else
            {
                tempTime = DateTime.Now;
            }
            timer1.Start();
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM