C# - 仅当文件完全复制到磁盘时才复制文件

Posted

技术标签:

【中文标题】C# - 仅当文件完全复制到磁盘时才复制文件【英文标题】:C# - Only copy file when it has been completely copied to disk 【发布时间】:2020-02-29 07:11:35 【问题描述】:

我正在编写一个等待将文件复制到文件夹的应用程序,当文件被复制后,我会尝试打开该文件。

我遇到了文件长度有时为零的问题。我相信这是因为文件没有完全完成复制到磁盘。

我已经按照https://***.com/a/937558/5330854 解决方案检查文件是否被锁定,但这仍然允许我打开长度为零的文件(我假设如果正在将文件复制到磁盘,那么当文件不为零时,这将被锁定,我将无法打开它)。

知道如何检查文件是否已完成复制到磁盘吗?

 while (stream == null && IsWithingTimeCap(startTime))
            
                stream = GetFileStream(fileInfo);
                if (stream == null)
                

                    Thread.Sleep(5000);

                
    

    if (fileInfo.Length == 0)
      
           //log
    


    private static Stream GetFileStream(IFileInfo fileInfo)
    
        Stream stream = null;

        try
        
            stream = fileInfo.Open(FileMode.Open, FileAccess.Read, FileShare.None);
        
        catch (IOException)
        
            //the file is unavailable because it is:
            //still being written to
            //or being processed by another thread
            //or does not exist (has already been processed)
            return null;
        

        return stream;
    

【问题讨论】:

感谢您抽出宝贵时间分享您的问题。但是您的问题中缺少一些东西。你的目标和困难是什么?到目前为止你做了什么?请尝试更好地解释您的问题、您的开发环境和数据结构,并分享更多代码(无截图)、一些示例、屏幕图像或草图以及用户故事或场景图。为了帮助您改进您的要求,请阅读右上角的 How do I ask a good question我避免提出的问题 您如何等待要复制的文件?文件系统观察者?什么是 fileInfo 以及如何以及何时获得它?可以多放点代码和场景顺序吗? 【参考方案1】:

A. FileSystemWatcher

您可以使用FileSystemWatcher Class 订阅对目标目录的更改。

但是,我不知道复制完成时您可以可靠地订阅的事件。 (另请注意,Copy 方法在最后一个事件之后返回,但这可能没问题)。

这是一个例子。

var fileName = "a.zip";
var src = "c:\\tmp\\src";
var dst = "c:\\tmp\\dst";


using (FileSystemWatcher watcher = new FileSystemWatcher())

    watcher.Path = dst;

    void OnChanged(object source, FileSystemEventArgs e) =>
            Console.WriteLine($"DateTime.Now:O, OnChanged, file: e.FullPath e.ChangeType, size: new System.IO.FileInfo(Path.Combine(dst,fileName)).Length");

    void OnCreated(object source, FileSystemEventArgs e) =>
            Console.WriteLine($"DateTime.Now:O, OnCreated, file: e.FullPath e.ChangeType, size: new System.IO.FileInfo(Path.Combine(dst,fileName)).Length");


    watcher.NotifyFilter = NotifyFilters.Size
                        | NotifyFilters.DirectoryName
                        | NotifyFilters.Attributes
                        | NotifyFilters.Size
                        | NotifyFilters.LastWrite
                        | NotifyFilters.LastAccess
                        | NotifyFilters.CreationTime
                        | NotifyFilters.Security
                        ;

    watcher.Changed += OnChanged;
    watcher.Created += OnCreated;

    // Begin watching.
    watcher.EnableRaisingEvents = true;

    Console.WriteLine($"DateTime.Now:O Let's start copying");
    var t = Task.Run(() => 
        Console.WriteLine($"DateTime.Now:O Copy start");
        System.IO.File.Copy(Path.Combine(src, fileName), Path.Combine(dst,fileName), overwrite: false);
        Console.WriteLine($"DateTime.Now:O Copy end");
    );

    await t;

    Console.ReadLine();

2019-11-04T10:54:26.4737696+10:00 Let's start copying
2019-11-04T10:54:26.4972070+10:00 Copy start
2019-11-04T10:54:26.5093223+10:00, OnChanged, file: c:\tmp\dst\a.zip Changed, size: 1232583046
2019-11-04T10:54:26.5195866+10:00, OnChanged, file: c:\tmp\dst\a.zip Changed, size: 1232583046
2019-11-04T10:54:30.6444434+10:00 Copy end
2019-11-04T10:54:30.5599570+10:00, OnChanged, file: c:\tmp\dst\a.zip Changed, size: 1232583046

B.零长度

你已经有了一个可能的答案:

我遇到了文件长度有时为零的问题。

您可以检查文件的长度并等待它不再为零。


虽然这不是严格的复制,但这里是 Firefox 下载文件期间的文件夹视图。

[![在此处输入图片描述][1]][1]

04/11/2019  10:01    <DIR>          .
04/11/2019  10:01    <DIR>          ..
04/11/2019  10:01                 0 SSMS-Setup-ENU.exe
04/11/2019  10:01        56,512,149 SSMS-Setup-ENU.exe.part
               2 File(s)     56,512,149 bytes

这是 Internet Explorer 正在下载的同一个文件。

04/11/2019  10:04    <DIR>          .
04/11/2019  10:04    <DIR>          ..
04/11/2019  10:04                 0 SSMS-Setup-ENU.exe.pz0u92s.partial
               1 File(s)              0 bytes

【讨论】:

以上是关于C# - 仅当文件完全复制到磁盘时才复制文件的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中通过网络复制文件夹中的文件

如何复制U盘

从本地复制到远程桌面时提示:无法复制文件,无法读取源文件或磁盘

c#如何复制文件夹到新目录

使用bat文件复制特定文本行?

将远程文件放入hadoop而不将其复制到本地磁盘