【问题标题】:CopyFileEx "The parameter is invalid" errorCopyFileEx“参数无效”错误
【发布时间】:2012-04-27 16:39:26
【问题描述】:

我正在编写一个(相当)简单的 C# 应用程序,使用 .NET 4 在运行可执行文件之前检查更新。如果网络共享上存在较新版本的 exe,只需将其复制到本地文件夹并启动它。一切都很完美,除了在阅读 File.Copy() 的限制时,我意识到我在执行此操作时无法显示进度条,而且我看到的所有内容都说使用 CopyFileEx,所以我我正在尝试这样做。

我使用了here 找到的示例代码,它编译得很好(尽管我仍然有点不确定后台工作程序到底是如何发挥作用的),除非我实际运行应用程序时,CopyFilEx() 方法返回false,错误为“参数不正确”。

我的代码(仅相关部分,如果需要我会添加更多)

调用函数:

XCopy.Copy(strServerAppPath + strExeName, strLocalAppPath + strExeName, true, true, (o,    pce) =>
{
worker.ReportProgress(pce.ProgressPercentage, strServerAppPath + strExeName);
});

(源路径为“C:\test.txt”,目标路径为“C:\test\test.txt”)

上面链接的代码中出现错误的地方:

bool result = CopyFileEx(Source, Destination, new CopyProgressRoutine(CopyProgressHandler), IntPtr.Zero, ref IsCancelled, copyFileFlags);
            if (!result)
                throw new Win32Exception(Marshal.GetLastWin32Error());

提前感谢您的帮助,我已经为此苦苦挣扎了几个小时...

【问题讨论】:

    标签: c# .net winapi copy


    【解决方案1】:

    与其处理所有的编组,不如“滚动你自己的”复印机逐块进行:

    private static void CopyFile(string source, string destination, int bytesPerChunk)
    {
        int bytesRead = 0;
    
        using (FileStream fs = new FileStream(source, FileMode.Open, FileAccess.Read))
        {
            using (BinaryReader br = new BinaryReader(fs))
            {
                using (FileStream fsDest = new FileStream(destination, FileMode.Create))
                {
                    BinaryWriter bw = new BinaryWriter(fsDest);
                    byte[] buffer;
    
                    for (int i = 0; i < fs.Length; i += bytesPerChunk)
                    {
                        buffer = br.ReadBytes(bytesPerChunk);
                        bw.Write(buffer);
                        bytesRead += bytesPerChunk;
                        ReportProgress(bytesRead, fs.Length);  //report the progress
                    }
                }
            }
        }
    }
    

    【讨论】:

    • 看起来很有趣...我之前也看到过类似的答案,但普遍的共识似乎是 copyfileex 更好(如果真的可以让它工作的话)。无论如何,我会试一试:)
    • 您最好使用ReadBytes(byte[],int,int) 方法,它可以重复使用相同的缓冲区,而不是为每个读取操作创建一个新数组。 (msdn.microsoft.com/en-us/library/ms143295.aspx)
    • 如何提高速度?与常规的 File.Copy 相比,它非常慢。 (我使用 20 MB 作为块值)
    • @DavidRTribble 你能解释一下吗?究竟可以怎样使用?
    • 一般来说,我会说 CopyEx 更好,因为它支持幕后的真正优化,而流不支持(例如 DMA)。
    【解决方案2】:

    不是调用ReadBytes(),它会在每次调用时分配一个新的byte[] 缓冲区数组,而是分配一个缓冲区(例如64KB 大小)并调用Read(buf, 0, buf.Length),它将读取最多buf.Length 个字节进入数组,然后返回实际读取的字节数。然后为每次读取重新使用相同的缓冲区数组(在将其内容写入目标流之后)。这样就不必为每个读/写操作重新分配一个新的缓冲区。

    示例

    例如,流复制方法的内部循环如下所示:

    byte[]  buf;
    
    // Allocate an I/O data buffer
    buf = new byte[64*1024];
    
    // Copy the contents of the input stream to the output stream
    for (;;)
    {
        int     len;
    
        // Read a block of data from the input stream
        len = inp.ReadBytes(buf, 0, buf.Length);
        if (len <= 0)
            break;
    
        // Write the data to the output stream
        outp.Write(buf, 0, len);
    }
    

    循环从输入流中读取多达 64KB 的字节到缓冲区,然后将读取的实际字节数写出到输出流中。每个读/写操作都使用相同的缓冲区,因此我们不会对缓冲区进行不必要的分配和释放。当读取操作失败时,我们已经到达输入流的末尾,所以我们退出循环。

    【讨论】:

    • @David R Tribble。提供ReportProgress(bytesRead, fs.Length) 的实现还是应该使用与 CopyFileEx 中相同的后台工作人员?
    猜你喜欢
    • 1970-01-01
    • 2011-12-14
    • 2016-08-17
    • 2016-01-05
    • 2020-10-16
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多