2012-04-27 139 views
2

我正在写一个(相当)简单的C#应用​​程序,使用.NET 4在运行可执行文件之前检查更新。如果网络共享上存在更新版本的exe,只需将其复制到本地文件夹并启动即可。除了在了解File.Copy()的局限性时,这一切都工作得很完美,我意识到当我这样做时我不能显示进度条,而且我看到的所有内容都表示使用CopyFileEx,米试图做到这一点。CopyFileEx“参数无效”错误

我使用的样例代码中发现here,它编译罚款(虽然我仍然BackgroundWorker的究竟是如何发挥作用的有点不确定),除了当我真正去运行应用程序时,CopyFilEx()方法返回错误,错误是“参数不正确”。

我的代码(有关章节而已,我会添加更多的如果需要的话)

调用函数:

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

(源路径的计算结果为 “C:\ test.txt的” 和的目标路径 “C:\测试\ test.txt的”)

凡在上面的代码链接错误发生:

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

在此先感谢您的帮助,我一直在为此奋斗了几个小时...

回答

3

与其处理所有的编组问题,只是“滚动您自己的”复印机块:

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 
       } 
      } 
     } 
    } 
} 
+0

看起来很有意思......我以前见过类似的答案,但一般认为似乎是copyfileex更好(如果真的可以让它工作)。不管怎么说,我都会试一试:) – Mansfield 2012-04-27 16:53:33

+0

它很有效,所以我会去用它。非常感谢! – Mansfield 2012-04-27 17:32:03

+2

使用'ReadBytes(byte [],int,int)'方法可能会更好,它可以重用相同的缓冲区,而不是为每个读操作创建一个新的数组。 (http://msdn.microsoft.com/en-us/library/ms143295.aspx) – 2012-04-27 20:34:58

3

与其说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从输入流的字节到缓冲,然后写出读取到输出流的实际字节数。每个读/写操作使用相同的缓冲区,所以我们不做不必要的分配和释放缓冲区。当读取操作失败时,我们已经到达输入流的末尾,所以我们退出循环。

+0

感谢您的提示! – Mansfield 2014-06-04 12:09:02

+0

@David R Tribble Pls。提供'ReportProgress(bytesRead,fs.Length)'的实现,还是应该使用与CopyFileEx中相同的后台工作器? – Khan 2015-02-09 09:37:57