复制大文件时的表单应用程序“不响应”?
-
20-08-2019 - |
题
我正在处理一个文件组织者应用程序。这些文件定期为500MB至2GB。一切正常,但是应用程序“停止响应”是非常烦人的。我想做的是每次读取/写入操作之后的字节或MEG by Meg by Meg by Meg copy。沿着这些台词,我不知道要使用的实际课程是什么,所以我只是要做一些东西:)
private void CopyFile(string inFilename, string outFilename)
{
FileReader inReader(inFilename);
FileWriter outWriter(outFilename, FileMode.OpenOrCreate);
byte theByte;
while (theByte = inReader.ReadByte())
{
outWriter.WriteByte(theByte, WriteMode.Append);
UpdateProgressBar();
Application.DoEvents();
}
inReader.CloseFile();
outWriter.CloseFile();
}
我知道这似乎是一件简单的事情,但是我一生中似乎找不到任何类型的例子,而无需使用直接的API呼叫或其他任何事情。我必须在这里缺少一些东西,所以如果有人可以让我走上正确的轨道,我将非常感谢。
提前致谢!
其他提示
您需要使用 BackownWorkerThread 实现这一目标。这是一个很好的例子: 使用背景工人线程复制文件
我想用 CopyFileEx
功能。如果在托管框架库中不存在对该功能的模拟,则无论如何如何使用它:也许是类似的文章 http://www.thetechscene.com/2008/09/copyfileex-with-progress-callback-inback-in-cusing-pinvoke/
我想使用的原因 CopyFileEx
是我认为它是在O/S内核中实现的,数据将在文件系统驱动程序中从一个文件复制到另一个文件,而无需使用用户存储器(更不用说托管内存)了。
threading.threadpool.queueuserworkitem应该让您走得好。
一种方法是在单独的线程中执行复制操作。当线程执行复制文件的工作时,您的主要应用程序将继续正常运行。当然,您想在线程和主应用程序之间添加通信,以便您可以更新进度栏或类似的反馈机制。
如果您不想处理多个线程,另一种方法是创建一个包含复制操作状态变量的类,以及一个从主应用程序定期调用的成员函数,以便每次称为一个字节。
除了运行背景线程外,您还应注意,您正在复制512m-2g的数据 一次一个字节. 。这将最多转化为2 十亿 打电话给ReadByte和WriteByte。希望那些电话缓冲区在某个地方,所以您不会做2 十亿 设法进行了不受管理的过渡,但即使如此,肯定会加起来。
记忆不是免费的,但这是肯定的,因为他们很便宜。分配一个缓冲区(也许是16k-64k),并将其复制成块。不,该代码并不像您需要处理一个不读取整个块的情况那样简单,但是我宁愿在2G上使用2G/64K方法调用。
您在这里有两个问题。首先是GUI线程在复制大文件时没有响应。您应该使用背景线程来解决该问题,如其他人所建议的。
另一个问题是您当前的文件复制例程不支持进度回调函数。以下问题的公认答案具有您编写自己的解决方案所需的信息:
我可以使用.net中的fileInfo.copyto()显示文件复制进度吗?
编辑:我刚刚找到了这个 CopyFileex的包装类. 。我测试了它,效果很好!
using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
namespace FileCopyTest {
public sealed class FileRoutines {
public static void CopyFile(FileInfo source, FileInfo destination) {
CopyFile(source, destination, CopyFileOptions.None);
}
public static void CopyFile(FileInfo source, FileInfo destination,
CopyFileOptions options) {
CopyFile(source, destination, options, null);
}
public static void CopyFile(FileInfo source, FileInfo destination,
CopyFileOptions options, CopyFileCallback callback) {
CopyFile(source, destination, options, callback, null);
}
public static void CopyFile(FileInfo source, FileInfo destination,
CopyFileOptions options, CopyFileCallback callback, object state) {
if (source == null) throw new ArgumentNullException("source");
if (destination == null)
throw new ArgumentNullException("destination");
if ((options & ~CopyFileOptions.All) != 0)
throw new ArgumentOutOfRangeException("options");
new FileIOPermission(
FileIOPermissionAccess.Read, source.FullName).Demand();
new FileIOPermission(
FileIOPermissionAccess.Write, destination.FullName).Demand();
CopyProgressRoutine cpr = callback == null ?
null : new CopyProgressRoutine(new CopyProgressData(
source, destination, callback, state).CallbackHandler);
bool cancel = false;
if (!CopyFileEx(source.FullName, destination.FullName, cpr,
IntPtr.Zero, ref cancel, (int)options)) {
throw new IOException(new Win32Exception().Message);
}
}
private class CopyProgressData {
private FileInfo _source = null;
private FileInfo _destination = null;
private CopyFileCallback _callback = null;
private object _state = null;
public CopyProgressData(FileInfo source, FileInfo destination,
CopyFileCallback callback, object state) {
_source = source;
_destination = destination;
_callback = callback;
_state = state;
}
public int CallbackHandler(
long totalFileSize, long totalBytesTransferred,
long streamSize, long streamBytesTransferred,
int streamNumber, int callbackReason,
IntPtr sourceFile, IntPtr destinationFile, IntPtr data) {
return (int)_callback(_source, _destination, _state,
totalFileSize, totalBytesTransferred);
}
}
private delegate int CopyProgressRoutine(
long totalFileSize, long TotalBytesTransferred, long streamSize,
long streamBytesTransferred, int streamNumber, int callbackReason,
IntPtr sourceFile, IntPtr destinationFile, IntPtr data);
[SuppressUnmanagedCodeSecurity]
[DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool CopyFileEx(
string lpExistingFileName, string lpNewFileName,
CopyProgressRoutine lpProgressRoutine,
IntPtr lpData, ref bool pbCancel, int dwCopyFlags);
}
public delegate CopyFileCallbackAction CopyFileCallback(
FileInfo source, FileInfo destination, object state,
long totalFileSize, long totalBytesTransferred);
public enum CopyFileCallbackAction {
Continue = 0,
Cancel = 1,
Stop = 2,
Quiet = 3
}
[Flags]
public enum CopyFileOptions {
None = 0x0,
FailIfDestinationExists = 0x1,
Restartable = 0x2,
AllowDecryptedDestination = 0x8,
All = FailIfDestinationExists | Restartable | AllowDecryptedDestination
}
}
您真正想做的是拥有一个多线程应用程序,并在背景线程中执行文件副本,这样您的主线程就不会被绑定。