12

我正在用 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;
        }

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

谢谢!

4

6 回答 6

9

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

像这样的东西应该工作:

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

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

于 2013-01-04T20:32:31.727 回答
1

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

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

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

于 2013-01-04T18:48:57.220 回答
1

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

//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
于 2013-01-04T20:13:51.213 回答
0

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

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

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

于 2013-01-04T19:24:01.347 回答
0

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

于 2013-01-04T20:55:20.240 回答
0

最近遇到了类似的问题。

OnBackupStarts();
//.. do stuff

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


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

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

于 2013-01-04T21:33:02.567 回答