【问题标题】:Why does FileInfo Length not match the TotalFileSize passed to progress of CopyFileEx为什么 FileInfo Length 与传递给 CopyFileEx 进度的 TotalFileSize 不匹配
【发布时间】:2020-01-04 23:44:22
【问题描述】:

我正在编写一个备份实用程序。这是我的第一个 c# 表单应用程序。

对于大多数文件,FileInfo length() 与传递给 CopyFileEx 进度处理程序的 TotalFileSize 相匹配。但是,对于一个文件,我发现 FileInfo length() 小于传递给进度处理程序的 TotalFileSize。

程序使用 FileInfo 计算要复制的所有文件的总大小 它使用带有进度处理程序的 CopyFileEx 来复制文件。 进度处理程序用于更新要复制的所有数据的比例的进度条。

我的问题是有时复制的字节总数大于预期的总数。

我的调查表明,对于大多数文件,FileInfo length() 与传递给进度处理程序的 TotalFileSize 相匹配。但是,对于一个文件,FileInfo length() 小于传递给进度处理程序的 TotalFileSize。

为什么大小不同?如何使计算的总文件大小与复制的总字节数相匹配?

    private UnsafeNativeMethods.CopyProgressResult localHandler(Int64 TotalFileSize, Int64 TotalBytesTransferred, Int64 StreamSize,
Int64 StreamBytesTransferred, UInt32 StreamNumber, UnsafeNativeMethods.CopyProgressCallbackReason CallbackReason, IntPtr SourceFile,
IntPtr DestinationFile, IntPtr Data)
    {
        switch (CallbackReason)
        {
            case UnsafeNativeMethods.CopyProgressCallbackReason.CallbackChunkedFinished:
                Debug.Print("localHandler: TotalBytesTransferred={0} TotalFileSize={1} ", TotalBytesTransferred.ToString(), TotalFileSize.ToString());
                break;
            case UnsafeNativeMethods.CopyProgressCallbackReason.CallbackStreamSwitch:
                break;
            default:
                break;
        }

        return UnsafeNativeMethods.CopyProgressResult.ProgressContinue;
    }

    private void ButtonTestFileSize_Click(object sender, EventArgs e)
    {
        bool success;
        bool b=false;
        string inputFile= @"C:\temp\WrongFileSize\myFile.conf";
        string outputFile= @"C:\temp\WrongFileSize\myFile.con2";


        /* Get the input Filename using FileInfo */
        FileInfo file = new FileInfo(inputFile);
        Debug.Print("input FileInfo.length={0}", file.Length);


        string hres = UnsafeNativeMethods.HResultToString(UnsafeNativeMethods.GetHResult((uint)Marshal.GetLastWin32Error()));
        success = UnsafeNativeMethods.CopyFileEx(inputFile,
                outputFile,
                new UnsafeNativeMethods.CopyProgressRoutine(localHandler),
                IntPtr.Zero,
                ref b,
                CopyFileFlags.FileFailIfExists | CopyFileFlags.COPY_FILE_NO_BUFFERING);
        if (!success)
        {
            Debug.Print("Failed");

        }
        else
        {

            Debug.Print("Success");
        }


        /* Get the output Filename using FileInfo */
        file = new FileInfo(outputFile);
        Debug.Print("outputFile FileInfo.length={0}", file.Length);

    }
}

这段代码的输出如下:

input FileInfo.length=2636
localHandler: TotalBytesTransferred=2636 TotalFileSize=2662 
localHandler: TotalBytesTransferred=2662 TotalFileSize=2662 
Success
outputFile FileInfo.length=2636

【问题讨论】:

    标签: c# file-copying fileinfo


    【解决方案1】:

    这是因为您复制的字节数多于文件的主要流中的字节数。 CopyFileEx 的LPPROGRESS_ROUTINE 的文档之间有一个提示:

    自复制操作开始以来,当前流中从源文件传输到目标文件的总字节数。

    以及您见证的输出:

    input FileInfo.length=2636
    localHandler: TotalBytesTransferred=2636 TotalFileSize=2662 
    localHandler: TotalBytesTransferred=2662 TotalFileSize=2662 
    Success
    outputFile FileInfo.length=2636
    

    如果您向当前空的UnsafeNativeMethods.CopyProgressCallbackReason.CallbackStreamSwitch 目标添加了一条消息,您会更清楚地看到发生了什么。基本上,您正在为主流传输 2636 个字节。大多数查看文件大小的 Win32 API 只报告主流,FileInfo() 在这里也不例外。

    然后您切换到文件上的某个辅助流,可能是:Zone.Identifier 流,因为这是从 Internet 下载并复制该流的 26 个字节时创建的通用流。

    您可以使用 Sysinternals 的 Streams tool 查看文件的不同流,或使用 FindFirstStream / FindNextStream 从代码中枚举它们。

    【讨论】:

    • 以上正确识别了问题。 (谢谢)我的主要问题是我不知道 NTFS 流。但是,它留下了我应该如何计算要提前复制的总字节数的问题。上面的答案让我想到了上一个问题[枚举 ADS](stackoverflow.com/questions/44270479/…)。我现在承认这个参考是同一个问题。响应包括计算将提前复制的总字节数的建议。我希望其他人会发现此参考资料有帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-14
    • 2014-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-01
    • 2013-08-12
    相关资源
    最近更新 更多