using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Linq; using System.Text; //using TheArtOfDev.HtmlRenderer.Adapters.Entities; namespace ryCommon { /// /// 大文件与批量文件操作类,支持中途取消操作,本类需要实例化操作 /// public class BigFileOp { /// /// 传输进度 /// /// 当前传输完成的值 /// 全部值,为-1表示无法获取 /// 当前传输的百分比,为-1表示无法获取 /// 当前下载速度(值为每秒下载的字节数),为-1表示无法获取 /// 携带的参数(可选) public delegate void TranProgressHandler(long curValue, long totalValue, double percent,long Speed=-1, object Tag=null); /// /// 传输失败的事件 /// /// 错误描述 /// 携带的参数(可选) public delegate void TranErrorHandler(Exception ex, object Tag = null); /// /// 文件传输出错 /// public event TranErrorHandler OnError; /// /// 文件传输进度 /// public event TranProgressHandler OnFileProgress; /// /// 文件夹传输进度 /// public event TranProgressHandler OnFolderProgress; /// /// 取消事件 /// public event CancelEventHandler OnCanel; /// /// 删除文件或文件夹 /// /// /// public bool DelFileOrFolder(string Path) { var result = false; try { if (System.IO.Directory.Exists(Path)) { System.IO.Directory.Delete(Path, true); result = !System.IO.Directory.Exists(Path); } else if (System.IO.File.Exists(Path)) { System.IO.File.Delete(Path); result = !System.IO.File.Exists(Path); } } catch { } return result; } /// /// 大文件按流复制文件,支持自动创建目标文件夹。 true:复制成功 false:复制失败 /// /// 原始文件路径 /// 复制目标文件路径 /// 携带的参数(可选) /// public bool CopyBigFile(string sourcePath, string targetPath,object Tag=null) { try { if(SkipSameFiles) { if (System.IO.File.Exists(targetPath)) { try { var target_info = new System.IO.FileInfo(targetPath); var source_info = new System.IO.FileInfo(sourcePath); if (target_info.Length == source_info.Length && target_info.LastWriteTimeUtc == source_info.LastWriteTimeUtc) { return true; } } catch { } } } var TranSize = 1024 * 1024 * 2;//每次读取2M //读取复制文件流 using (FileStream fsRead = new FileStream(sourcePath, FileMode.Open, FileAccess.Read)) { if (System.IO.File.Exists(targetPath)) { if (!DelFileOrFolder(targetPath)) { return false; } } CreateDirectory(System.IO.Path.GetDirectoryName(targetPath)); OnFileProgress?.Invoke(0, fsRead.Length, 0,0, Tag); var totalSize = fsRead.Length; var curSize = 0L; var dt = DateTime.Now; var speed = 0L;//复制速度 var last_size = 0L; //写入文件复制流 using (FileStream fsWrite = new FileStream(targetPath, FileMode.OpenOrCreate, FileAccess.Write)) { byte[] buffer = new byte[TranSize]; CancelEventArgs e1 = new CancelEventArgs(); //可能文件比较大,要循环读取,每次读取2M while (true) { if (OnCanel != null) { OnCanel?.Invoke(this, e1); if (e1.Cancel) { fsWrite.Close(); DelFileOrFolder(targetPath); break; } } //每次读取的数据 n:是每次读取到的实际数据大小 int n = fsRead.Read(buffer, 0, buffer.Count()); //如果n=0说明读取的数据为空,已经读取到最后了,跳出循环 if (n == 0) { break; } curSize += n; var dt_now = DateTime.Now; if (dt.AddSeconds(1) /// 复制文件夹到目标文件夹,不支持进度事件,支持中途取消 /// /// 源文件夹 /// 目标文件夹 /// 返回复制操作是否成功的标识,成功返回0,负数表示复制失败的文件数量。1表示源文件夹不存在 public int CopyFolder(string fromDir, string ToDir) { return CopyFolder(fromDir,ToDir,-1,out _); } /// /// 复制文件或文件夹到目标路径,不支持进度事件,支持中途取消 /// /// 源路径 /// 目标路径 /// 返回复制操作是否成功的标识,成功返回0,负数表示复制失败的文件数量。1表示源文件夹不存在 public int CopyFileOrFolder(string fromPath, string ToPath) { if(System.IO.File.Exists(fromPath)) { return CopyBigFile(fromPath, ToPath)?0:-1; } else if (System.IO.Directory.Exists(fromPath)) { return CopyFolder(fromPath, ToPath, -1, out _); } else { return 1; } } /// /// 复制文件夹到目标文件夹,支持进度事件,支持中途取消 /// /// 源文件夹 /// 目标文件夹 /// 返回复制操作是否成功的标识,成功返回0,负数表示复制失败的文件数量。1表示源文件夹不存在 public int CopyFolderByProgress(string fromDir, string ToDir) { var FileCount = GetFilesCount(fromDir); return CopyFolder(fromDir, ToDir, FileCount, out _); } /// /// 如果指定文件夹不存在,则创建文件夹 /// /// public static void CreateDirectory(string path) { if (!System.IO.File.Exists(path) && !System.IO.Directory.Exists(path)) { try { System.IO.Directory.CreateDirectory(path); } catch { } } } /// /// 是否跳过相同文件,默认不跳过(根据文件大小和修改时间来判断) /// public bool SkipSameFiles { get; set; } = false; public readonly List ErrFilesList = new List(); /// /// 复制文件夹到目标文件夹,支持中途取消 /// /// 源文件夹 /// 目标文件夹 /// 总数量,如果不计算,则使用-1 /// 操作的数量,包含成功的和失败的 /// 携带的参数(可选) /// 返回复制操作是否成功的标识,成功返回0,负数表示复制失败的文件数量。1表示源文件夹不存在 private int CopyFolder(string fromDir, string ToDir,int TotalCount, out int Count,object Tag = null) { Count = 0; var _count = 0; var error = 0; Copy(fromDir, ToDir); Count = _count; return -error; int Copy(string From_Dir, string To_Dir) { var _fromDir = From_Dir.TrimEnd('\\'); var _ToDir = To_Dir.TrimEnd('\\'); if (!Directory.Exists(_fromDir)) { return 1; } var files = Directory.GetFiles(_fromDir); CancelEventArgs e1 = new CancelEventArgs(); CreateDirectory(_ToDir); foreach (var file in files) { if (OnCanel != null) { OnCanel?.Invoke(this, e1); if (e1.Cancel) { break; } } if (!CopyBigFile(file, _ToDir + "\\" + Path.GetFileName(file), Tag)) { error++; ErrFilesList.Add(_ToDir + "\\" + Path.GetFileName(file)); } _count++; var percent = 0d; if (TotalCount > 0) { percent = _count / (double)TotalCount; } else if (TotalCount == -1) { percent = -1; } OnFolderProgress?.Invoke(_count, TotalCount, percent, -1, Tag); } var dirs = Directory.GetDirectories(_fromDir); foreach (var dir in dirs) { int result = Copy(dir, _ToDir + "\\" + Path.GetFileName(dir)); if (OnCanel != null) { OnCanel?.Invoke(this, e1); if (e1.Cancel) { break; } } } return -error; } } /// /// 获取文件夹中的文件数量 /// /// 文件夹路径 /// 返回文件数量,中途取消则返回-1 public int GetFilesCount(string Dir) { var _fromDir = Dir.TrimEnd('\\'); if (!Directory.Exists(_fromDir)) { return 0; } var files = Directory.GetFiles(_fromDir); var count = 0; CancelEventArgs e1 = new CancelEventArgs(); count += files.Length; var dirs = Directory.GetDirectories(_fromDir); foreach (var dir in dirs) { if (OnCanel != null) { OnCanel?.Invoke(this, e1); if (e1.Cancel) { count = -1; break; } } var result= GetFilesCount(dir); if (result == -1) { count = -1;break; } count+= result; } return count; } /// /// 获取文件大小 /// /// /// public static long GetFileSize(string path) { try { FileInfo fileInfo = new FileInfo(path); return fileInfo.Length; } catch { return -1; } } /// /// 获取文件夹的大小 /// /// 文件夹路径 /// 返回文件数量,中途取消则返回-1 public long GetFolderSize(string Dir) { var _fromDir = Dir.TrimEnd('\\'); if (!Directory.Exists(_fromDir)) { return 0; } var files = Directory.GetFiles(_fromDir); var size = 0L; CancelEventArgs e1 = new CancelEventArgs(); for (int i = 0; i < files.Length; i++) { if (OnCanel != null && i %5==0) { OnCanel?.Invoke(this, e1); if (e1.Cancel) { size = -1; break; } } size +=GetFileSize(files[i]); } var dirs = Directory.GetDirectories(_fromDir); foreach (var dir in dirs) { if (OnCanel != null) { OnCanel?.Invoke(this, e1); if (e1.Cancel) { size = -1; break; } } var result = GetFilesCount(dir); if (result == -1) { size = -1; break; } size += result; } return size; } /// /// 添加文件到指定文件夹,会进行自动重命名,并返回重命名后的文件名(含路径) /// /// 要添加的文件路径 /// 要添加到的文件夹 /// 是否根据时间进行重命名 /// 返回是否成功执行 /// 成功执行则返回路径,否则返回空 public string AddFileToFolder(string filepath, string toFolder, bool RenameByTime, out bool OK) { OK = false; var _toFolder = toFolder.TrimEnd('\\'); CreateDirectory(_toFolder); if (!System.IO.Directory.Exists(_toFolder)) { return ""; } if (!System.IO.File.Exists(filepath) && !System.IO.Directory.Exists(filepath)) { return ""; } var filename = System.IO.Path.GetFileName(filepath); if (RenameByTime) { filename = DateTime.Now.ToString("yyyyMMddHHmmss") + System.IO.Path.GetExtension(filepath); } if (!System.IO.File.Exists(_toFolder + "\\" + filename) && !System.IO.Directory.Exists(_toFolder + "\\" + filename)) { if (CopyBigFile(filepath, _toFolder + "\\" + filename)) { OK = true; return _toFolder + "\\" + filename; } return "";//如果复制失败,则返回空路径 } else //如果目标路径已经存在同名文件 { int index = 0; string filename_noext; if (RenameByTime) { filename_noext = DateTime.Now.ToString("yyyyMMddHHmmss"); } else { filename_noext = System.IO.Path.GetFileNameWithoutExtension(filepath); } var ext = System.IO.Path.GetExtension(filepath); CancelEventArgs e1 = new CancelEventArgs(); while (index < 20) //最多重试20次 { if (OnCanel != null) { OnCanel?.Invoke(this, e1); if (e1.Cancel) { break; } } Random rd = new Random(Guid.NewGuid().GetHashCode()); if (RenameByTime) { filename_noext = DateTime.Now.ToString("yyyyMMddHHmmss"); } var to_path = _toFolder + "\\" + filename_noext + "_" + rd.Next(1000, 9999) + ext; if (!System.IO.File.Exists(to_path) && !System.IO.Directory.Exists(to_path)) { if (CopyBigFile(filepath, to_path)) { OK = true; return to_path; } return ""; } index++; } return ""; } } } }