wpf System.IO.File.Move--如何等待移动完成?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14162983/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 06:54:00  来源:igfitidea点击:

System.IO.File.Move--How to wait for move completion?

c#wpf

提问by Mizmor

I am writing a WPF application in c# and I need to move some files--the rub is that I really REALLY need to know if the files make it. To do this, I wrote a check that makes sure that the file gets to the target directory after the move--the problem is that sometimes I get to the check before the file finishes moving:

我正在用 c# 编写一个 WPF 应用程序,我需要移动一些文件——问题是我真的需要知道这些文件是否成功。为此,我编写了一个检查,以确保文件在移动后到达目标目录——问题是有时我在文件完成移动之前进行检查:

   System.IO.File.Move(file.FullName, endLocationWithFile);

            System.IO.FileInfo[] filesInDirectory = endLocation.GetFiles();
            foreach (System.IO.FileInfo temp in filesInDirectory)
            {
                if (temp.Name == shortFileName)
                {

                    return true;
                }
            }

            // The file we sent over has not gotten to the correct   directory....something went wrong!
            throw new IOException("File did not reach destination");

        }
        catch (Exception e)
        {
            //Something went wrong, return a fail;
            logger.writeErrorLog(e);
            return false;
        }

Could somebody tell me how to make sure that the file actually gets to the destination?--The files that I will be moving could be VERY large--(Full HD mp4 files of up to 2 hours)

有人能告诉我如何确保文件确实到达目的地吗?--我将要移动的文件可能非常大--(长达 2 小时的全高清 mp4 文件)

Thanks!

谢谢!

采纳答案by sa_ddam213

You could use streams with AysncAwaitto ensure the file is completely copied

您可以使用流AysncAwait来确保文件被完全复制

Something like this should work:

这样的事情应该工作:

private void Button_Click(object sender, RoutedEventArgs e)
{
    string sourceFile = @"\HOMESERVER\Development Backup\Software\Microsoft\en_expression_studio_4_premium_x86_dvd_537029.iso";
    string destinationFile = "G:\en_expression_studio_4_premium_x86_dvd_537029.iso";

    MoveFile(sourceFile, destinationFile);
}

private async void MoveFile(string sourceFile, string destinationFile)
{
    try
    {
        using (FileStream sourceStream = File.Open(sourceFile, FileMode.Open))
        {
            using (FileStream destinationStream = File.Create(destinationFile))
            {
                await sourceStream.CopyToAsync(destinationStream);
                if (MessageBox.Show("I made it in one piece :), would you like to delete me from the original file?", "Done", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
                {
                    sourceStream.Close();
                    File.Delete(sourceFile);
                }
            }
        }
    }
    catch (IOException ioex)
    {
        MessageBox.Show("An IOException occured during move, " + ioex.Message);
    }
    catch (Exception ex)
    {
        MessageBox.Show("An Exception occured during move, " + ex.Message);
    }
}

If your using VS2010 you will have to install Async CTPto use the new Async/Await syntax

如果您使用 VS2010,则必须安装Async CTP才能使用新的 Async/Await 语法

回答by Eric J.

You could watch for the files to disappear from the original directory, and then confirm that they indeed appeared in the target directory.

您可以观察文件从原始目录中消失,然后确认它们确实出现在目标目录中。

I have not had great experience with file watchers. I would probably have the thread doing the move wait for an AutoResetEventwhile a separate thread or timer runs to periodically check for the files to disappear from the original location, check that they are in the new location, and perhaps (depending on your environment and needs) perform a consistency check (e.g. MD5 check) of the files. Once those conditions are satisfied, the "checker" thread/timer would trigger the AutoResetEvent so that the original thread can progress.

我对文件观察者没有很好的经验。我可能会让执行移动的线程等待AutoResetEvent,而一个单独的线程或计时器运行以定期检查文件是否从原始位置消失,检查它们是否在新位置,也许(取决于您的环境和需要)执行文件的一致性检查(例如 MD5 检查)。一旦满足这些条件,“检查器”线程/计时器将触发 AutoResetEvent,以便原始线程可以进行。

Include some "this is taking way too long" logic in the "checker".

在“检查器”中包含一些“这需要太长时间”的逻辑。

回答by spender

Why not manage the copy yourself by copying streams?

为什么不通过复制流来自己管理副本?

//http://www.dotnetthoughts.net/writing_file_with_non_cache_mode_in_c/
const FileOptions FILE_FLAG_NO_BUFFERING = (FileOptions) 0x20000000;

//experiment with different buffer sizes for optimal speed
var bufLength = 4096;

using(var outFile = 
    new FileStream(
        destPath,
        FileMode.Create, 
        FileAccess.Write, 
        FileShare.None, 
        bufLength, 
        FileOptions.WriteThrough | FILE_FLAG_NO_BUFFERING))
using(var inFile = File.OpenRead(srcPath))
{
    //either
    //inFile.CopyTo(outFile);

    //or
    var fileSizeInBytes = inFile.Length;
    var buf = new byte[bufLength];
    long totalCopied = 0L;
    int amtRead;
    while((amtRead = inFile.Read(buf,0,bufLength)) > 0)
    {
        outFile.Write(buf,0,amtRead);
        totalCopied += amtRead;
        double progressPct = 
            Convert.ToDouble(totalCopied) * 100d / fileSizeInBytes;
        progressPct.Dump();
    }
}
//file is written

回答by Chris

You most likely want the move to happen in a separate thread so that you aren't stopping the execution of your application for hours.

您很可能希望移动发生在一个单独的线程中,这样您就不会停止应用程序的执行数小时。

If the program cannot continue without the move being completed, then you could open a dialog and check in on the move thread periodically to update a progress tracker. This provides the user with feedback and will prevent them from feeling as if the program has frozen.

如果程序在移动未完成的情况下无法继续,那么您可以打开一个对话框并定期检查移动线程以更新进度跟踪器。这为用户提供了反馈,并防止他们感觉好像程序已经冻结。

There's info and an example on this here: http://hintdesk.com/c-wpf-copy-files-with-progress-bar-by-copyfileex-api/

这里有信息和示例:http: //hintdesk.com/c-wpf-copy-files-with-progress-bar-by-copyfileex-api/

回答by Yaron Wittenstein

try checking periodically in a background task whether the copied file size reached the file size of the original file (you can add hashes comparing between the files)

尝试在后台任务中定期检查复制的文件大小是否达到原始文件的文件大小(您可以在文件之间添加哈希比较)

回答by Lucas

Got similar problem recently.

最近遇到了类似的问题。

OnBackupStarts();
//.. do stuff

 new TaskFactory().StartNew(() =>
                {
                    OnBackupStarts()
                    //.. do stuff
                    OnBackupEnds();
                });


void OnBackupEnds()
    {
        if (BackupChanged != null)
        {
            BackupChanged(this, new BackupChangedEventArgs(BackupState.Done));
        }
    }

do not wait, react to event

不要等待,对事件做出反应