简体   繁体   English

为什么FileInfo Length与传递给CopyFileEx进度的TotalFileSize不匹配

[英]Why does FileInfo Length not match the TotalFileSize passed to progress of CopyFileEx

I am writing a backup utility. 我正在编写一个备份实用程序。 It is my first c# forms application. 这是我的第一个C#表单应用程序。

For most files FileInfo length() matches the TotalFileSize passed to the CopyFileEx progress handler. 对于大多数文件,FileInfo length()与传递给CopyFileEx进度处理程序的TotalFileSize相匹配。 However, for just one file Ihave found that FileInfo length() is less than the TotalFileSize passed to the progress handler. 但是,对于仅一个文件,我发现FileInfo length()小于传递给进度处理程序的TotalFileSize。

The program uses FileInfo to calculate the total size of all files to be copied It uses CopyFileEx with a progress handler to copy files. 该程序使用FileInfo来计算要复制的所有文件的总大小。它将CopyFileEx与进度处理程序一起使用来复制文件。 The progress handler is used to update a progress bar for the proportion of all the data to be copied. 进度处理程序用于为所有要复制的数据的比例更新进度条。

My problem is that sometimes the total number of bytes copied is greater than the total expected. 我的问题是有时复制的字节总数大于预期的总数。

My investigation show that for most files FileInfo length() matches the TotalFileSize passed to the progress handler. 我的调查表明,对于大多数文件,FileInfo length()与传递给进度处理程序的TotalFileSize相匹配。 However, for just one file FileInfo length() is less than the TotalFileSize passed to the progress handler. 但是,对于一个文件,FileInfo length()小于传递给进度处理程序的TotalFileSize。

Why do the sizes differ and what can I do to make the the total file size calculated match the total bytes copied? 为什么大小不同?我该怎么做才能使计算出的文件总大小与复制的总字节数匹配?

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

    }
}

The output from this code is as follows: 此代码的输出如下:

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

This is because you're copying more bytes than is in the primary stream of the file. 这是因为您要复制的字节数比文件的主要流中的字节数多。 There's a hint between the documentation for CopyFileEx's LPPROGRESS_ROUTINE : 在CopyFileEx的LPPROGRESS_ROUTINE的文档之间有一个提示:

The total number of bytes in the current stream that have been transferred from the source file to the destination file since the copy operation began. 自复制操作开始以来,当前流中已从源文件传输到目标文件的字节总数。

and the output you witness: 和您看到的输出:

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

If you added a message to your currently empty UnsafeNativeMethods.CopyProgressCallbackReason.CallbackStreamSwitch target, you'd more obviously see what's going on. 如果您向当前为空的UnsafeNativeMethods.CopyProgressCallbackReason.CallbackStreamSwitch目标添加了一条消息,那么您显然会发现正在发生的事情。 Basically, you're transferring 2636 bytes for the primary stream. 基本上,您正在为主要流传输2636字节。 Most of the Win32 APIs that look at file size only report on the primary stream, and FileInfo() is no different here. 大多数查看文件大小的Win32 API仅在主要流上报告,而FileInfo()在这里没有什么不同。

Then you switch to some secondary stream on the file, probably a :Zone.Identifier stream, since that's the common stream created when downloading from the internet, and copying the 26 bytes of that stream. 然后,您切换到文件上的一些辅助流,可能是:Zone.Identifier流,因为这是从Internet下载并复制该流的26个字节时创建的普通流。

You can use the Streams tool from Sysinternals to view the different streams for a file, or use FindFirstStream / FindNextStream to enumerate them from code. 您可以使用Sysinternals中的Streams工具查看文件的不同流,或者使用FindFirstStream / FindNextStream从代码中枚举它们。

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

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