pat*_*ero 33 c# file-io backgroundworker file-copying progress-bar
我用过这段代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.IO;
namespace WindowsApplication1 {
public partial class Form1 : Form {
// Class to report progress
private class UIProgress {
public UIProgress(string name_, long bytes_, long maxbytes_) {
name = name_; bytes = bytes_; maxbytes = maxbytes_;
}
public string name;
public long bytes;
public long maxbytes;
}
// Class to report exception {
private class UIError {
public UIError(Exception ex, string path_) {
msg = ex.Message; path = path_; result = DialogResult.Cancel;
}
public string msg;
public string path;
public DialogResult result;
}
private BackgroundWorker mCopier;
private delegate void ProgressChanged(UIProgress info);
private delegate void CopyError(UIError err);
private ProgressChanged OnChange;
private CopyError OnError;
public Form1() {
InitializeComponent();
mCopier = new BackgroundWorker();
mCopier.DoWork += Copier_DoWork;
mCopier.RunWorkerCompleted += Copier_RunWorkerCompleted;
mCopier.WorkerSupportsCancellation = true;
OnChange += Copier_ProgressChanged;
OnError += Copier_Error;
button1.Click += button1_Click;
ChangeUI(false);
}
private void Copier_DoWork(object sender, DoWorkEventArgs e) {
// Create list of files to copy
string[] theExtensions = { "*.jpg", "*.jpeg", "*.bmp", "*.png", "*.gif" };
List<FileInfo> files = new List<FileInfo>();
string path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
DirectoryInfo dir = new DirectoryInfo(path);
long maxbytes = 0;
foreach (string ext in theExtensions) {
FileInfo[] folder = dir.GetFiles(ext, SearchOption.AllDirectories);
foreach (FileInfo file in folder) {
if ((file.Attributes & FileAttributes.Directory) != 0) continue;
files.Add(file);
maxbytes += file.Length;
}
}
// Copy files
long bytes = 0;
foreach (FileInfo file in files) {
try {
this.BeginInvoke(OnChange, new object[] { new UIProgress(file.Name, bytes, maxbytes) });
File.Copy(file.FullName, @"c:\temp\" + file.Name, true);
}
catch (Exception ex) {
UIError err = new UIError(ex, file.FullName);
this.Invoke(OnError, new object[] { err });
if (err.result == DialogResult.Cancel) break;
}
bytes += file.Length;
}
}
private void Copier_ProgressChanged(UIProgress info) {
// Update progress
progressBar1.Value = (int)(100.0 * info.bytes / info.maxbytes);
label1.Text = "Copying " + info.name;
}
private void Copier_Error(UIError err) {
// Error handler
string msg = string.Format("Error copying file {0}\n{1}\nClick OK to continue copying files", err.path, err.msg);
err.result = MessageBox.Show(msg, "Copy error", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);
}
private void Copier_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
// Operation completed, update UI
ChangeUI(false);
}
private void ChangeUI(bool docopy) {
label1.Visible = docopy;
progressBar1.Visible = docopy;
button1.Text = docopy ? "Cancel" : "Copy";
label1.Text = "Starting copy...";
progressBar1.Value = 0;
}
private void button1_Click(object sender, EventArgs e) {
bool docopy = button1.Text == "Copy";
ChangeUI(docopy);
if (docopy) mCopier.RunWorkerAsync();
else mCopier.CancelAsync();
}
}
}
Run Code Online (Sandbox Code Playgroud)
发布在这里(nobugz发布的那个)复制文件并在进度条中显示状态.
我希望在复制时不断增加进度条的值,尤其是大文件.此示例代码中发生的情况是进度条中的值在复制的每个文件上停止,并且在复制一个文件之后,它将增加到要复制的下一个文件的大小.我希望它像CopyFileExWindows 一样工作,复制时进度条不断增加(我不能使用CopyFileEx因为我想拥有自己的实现).
Ant*_*nov 43
你需要这样的东西:
public delegate void ProgressChangeDelegate(double Persentage, ref bool Cancel);
public delegate void Completedelegate();
class CustomFileCopier
{
public CustomFileCopier(string Source, string Dest)
{
this.SourceFilePath = Source;
this.DestFilePath = Dest;
OnProgressChanged += delegate { };
OnComplete += delegate { };
}
public void Copy()
{
byte[] buffer = new byte[1024 * 1024]; // 1MB buffer
bool cancelFlag = false;
using (FileStream source = new FileStream(SourceFilePath, FileMode.Open, FileAccess.Read))
{
long fileLength = source.Length;
using (FileStream dest = new FileStream(DestFilePath, FileMode.CreateNew, FileAccess.Write))
{
long totalBytes = 0;
int currentBlockSize = 0;
while ((currentBlockSize = source.Read(buffer, 0, buffer.Length)) > 0)
{
totalBytes += currentBlockSize;
double persentage = (double)totalBytes * 100.0 / fileLength;
dest.Write(buffer, 0, currentBlockSize);
cancelFlag = false;
OnProgressChanged(persentage, ref cancelFlag);
if (cancelFlag == true)
{
// Delete dest file here
break;
}
}
}
}
OnComplete();
}
public string SourceFilePath { get; set; }
public string DestFilePath { get; set; }
public event ProgressChangeDelegate OnProgressChanged;
public event Completedelegate OnComplete;
}
Run Code Online (Sandbox Code Playgroud)
只需在单独的线程中运行它并订阅OnProgressChanged事件.
tod*_*dmo 25
我喜欢这个解决方案,因为
public delegate void IntDelegate(int Int);
public static event IntDelegate FileCopyProgress;
public static void CopyFileWithProgress(string source, string destination)
{
var webClient = new WebClient();
webClient.DownloadProgressChanged += DownloadProgress;
webClient.DownloadFileAsync(new Uri(source), destination);
}
private static void DownloadProgress(object sender, DownloadProgressChangedEventArgs e)
{
if(FileCopyProgress != null)
FileCopyProgress(e.ProgressPercentage);
}
Run Code Online (Sandbox Code Playgroud)
只要设置了权限,这应该适用于UNC路径.如果没有,您将收到此错误,在这种情况下,我投票支持经过身份验证的请求用户路由.
System.UnauthorizedAccessException:拒绝访问路径'\ testws01\c $\foo'.ASP.NET无权访问所请求的资源.考虑将资源的访问权限授予ASP.NET请求标识.ASP.NET具有基本进程标识(IIS 5上通常为{MACHINE}\ASPNET,IIS 6和IIS 7上为网络服务,IIS 7.5上已配置的应用程序池标识),如果应用程序未模拟,则使用该标识.如果应用程序模拟通过
<identity impersonate="true"/>,则标识将是匿名用户(通常为IUSR_MACHINENAME)或经过身份验证的请求用户.
通过使用Gal提供的2个流来制作自己的文件复制逻辑是一个可行的选择,但不建议仅仅因为有一个深度集成的Windows操作,它在可靠性,安全性和性能方面进行了优化,名为CopyFileEx.
在下面的文章中说:http://msdn.microsoft.com/en-us/magazine/cc163851.aspx他们完全按照你的意愿行事,但当然你必须使用CopyFileEx
祝好运
**编辑**(修复我的答案,严重失误)
这是一个优化的解决方案,它利用 .NET 扩展和双缓冲区来获得更好的性能。一个新的 CopyTo 重载被添加到 FileInfo 中,并带有一个仅在更改时指示进度的操作。
WPF 中的此示例实现带有一个名为 progressBar1 的进度条,用于在后台执行复制操作。
private FileInfo _source = new FileInfo(@"C:\file.bin");
private FileInfo _destination = new FileInfo(@"C:\file2.bin");
private void CopyFile()
{
if(_destination.Exists)
_destination.Delete();
Task.Run(()=>{
_source.CopyTo(_destination, x=>Dispatcher.Invoke(()=>progressBar1.Value = x));
}).GetAwaiter().OnCompleted(() => MessageBox.Show("File Copied!"));
}
Run Code Online (Sandbox Code Playgroud)
这是控制台应用程序的示例
class Program
{
static void Main(string[] args)
{
var _source = new FileInfo(@"C:\Temp\bigfile.rar");
var _destination = new FileInfo(@"C:\Temp\bigfile2.rar");
if (_destination.Exists) _destination.Delete();
_source.CopyTo(_destination, x => Console.WriteLine($"{x}% Complete"));
Console.WriteLine("File Copied.");
}
}
Run Code Online (Sandbox Code Playgroud)
要使用,请创建一个新文件,例如 FileInfoExtensions.cs 并添加以下代码:
public static class FileInfoExtensions
{
public static void CopyTo(this FileInfo file, FileInfo destination, Action<int> progressCallback)
{
const int bufferSize = 1024 * 1024; //1MB
byte[] buffer = new byte[bufferSize], buffer2 = new byte[bufferSize];
bool swap = false;
int progress = 0, reportedProgress = 0, read = 0;
long len = file.Length;
float flen = len;
Task writer = null;
using (var source = file.OpenRead())
using (var dest = destination.OpenWrite())
{
dest.SetLength(source.Length);
for (long size = 0; size < len; size += read)
{
if ((progress = ((int)((size / flen) * 100))) != reportedProgress)
progressCallback(reportedProgress = progress);
read = source.Read(swap ? buffer : buffer2, 0, bufferSize);
writer?.Wait(); // if < .NET4 // if (writer != null) writer.Wait();
writer = dest.WriteAsync(swap ? buffer : buffer2, 0, read);
swap = !swap;
}
writer?.Wait(); //Fixed - Thanks @sam-hocevar
}
}
}
Run Code Online (Sandbox Code Playgroud)
双缓冲区通过使用一个线程读取和一个线程写入来工作,因此最大速度仅取决于两者中较慢的一个。使用了两个缓冲区(一个双缓冲区),确保读写线程永远不会同时使用同一个缓冲区。
示例:代码读入缓冲区 1,然后当读完成时,写操作开始写入缓冲区 1 的内容。无需等待写入完成,缓冲区被交换到缓冲区 2,数据被读入缓冲区 2,而缓冲区 1 还在正在写。一旦缓冲区 2 中的读取完成,它将等待缓冲区 1 上的写入完成,然后开始写入缓冲区 2,然后重复该过程。本质上,1 个线程始终在读取,一个线程始终在写入。
WriteAsync使用重叠 I/O,它利用I/O 完成端口,它依赖硬件而不是线程来执行异步操作,因此非常高效。TLDR:我谎称有 2 个线程,但概念是相同的。
| 归档时间: |
|
| 查看次数: |
82424 次 |
| 最近记录: |