2022-05-26 09:12:39 +00:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
|
using System.IO;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
|
|
|
|
|
|
namespace ryCommon
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 大文件与批量文件操作类,支持中途取消操作,本类需要实例化操作
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class BigFileOp
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 传输进度
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="curValue">当前传输完成的值</param>
|
|
|
|
|
|
/// <param name="totalValue">全部值,为-1表示无法获取</param>
|
|
|
|
|
|
/// <param name="percent">当前传输的百分比,为-1表示无法获取</param>
|
|
|
|
|
|
public delegate void TranProgressHandler(long curValue, long totalValue, double percent);
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 传输进度
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static event TranProgressHandler OnProgress;
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 取消事件
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static event CancelEventHandler OnCanel;
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 大文件按流复制文件,支持自动创建目标文件夹。 true:复制成功 false:复制失败
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="soucrePath">原始文件路径</param>
|
|
|
|
|
|
/// <param name="targetPath">复制目标文件路径</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public bool CopyBigFile(string soucrePath, string targetPath)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var TranSize = 1024 * 1024 * 2;//每次读取2M
|
|
|
|
|
|
//读取复制文件流
|
|
|
|
|
|
using (FileStream fsRead = new FileStream(soucrePath, FileMode.Open, FileAccess.Read))
|
|
|
|
|
|
{
|
2023-11-07 08:36:50 +00:00
|
|
|
|
if (System.IO.File.Exists(targetPath))
|
2022-05-26 09:12:39 +00:00
|
|
|
|
{
|
2023-11-07 08:36:50 +00:00
|
|
|
|
if (RyFiles.DeleteFile(targetPath) != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2022-05-26 09:12:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
RyFiles.CreateDirectory(System.IO.Path.GetDirectoryName(targetPath));
|
|
|
|
|
|
OnProgress?.Invoke(0, fsRead.Length, 0);
|
|
|
|
|
|
var totalSize = fsRead.Length;
|
|
|
|
|
|
//写入文件复制流
|
|
|
|
|
|
using (FileStream fsWrite = new FileStream(targetPath, FileMode.OpenOrCreate, FileAccess.Write))
|
|
|
|
|
|
{
|
|
|
|
|
|
byte[] buffer = new byte[TranSize];
|
|
|
|
|
|
var curSize = 0L;
|
|
|
|
|
|
CancelEventArgs e1 = new CancelEventArgs();
|
|
|
|
|
|
//可能文件比较大,要循环读取,每次读取2M
|
|
|
|
|
|
while (true)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (OnCanel != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
OnCanel?.Invoke(this, e1);
|
|
|
|
|
|
if (e1.Cancel) {
|
|
|
|
|
|
fsWrite.Close();
|
|
|
|
|
|
RyFiles.DeleteFile(targetPath);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
//每次读取的数据 n:是每次读取到的实际数据大小
|
|
|
|
|
|
int n = fsRead.Read(buffer, 0, buffer.Count());
|
|
|
|
|
|
//如果n=0说明读取的数据为空,已经读取到最后了,跳出循环
|
|
|
|
|
|
if (n == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
curSize += n;
|
|
|
|
|
|
OnProgress?.Invoke(curSize, totalSize, totalSize == 0 ? 0 : curSize / (double)totalSize);
|
|
|
|
|
|
//写入每次读取的实际数据大小
|
|
|
|
|
|
fsWrite.Write(buffer, 0, n);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
OnProgress?.Invoke(totalSize, totalSize, 100);
|
|
|
|
|
|
if (!System.IO.File.Exists(targetPath))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 复制文件夹到目标文件夹,不支持进度事件,支持中途取消
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="fromDir">源文件夹</param>
|
|
|
|
|
|
/// <param name="ToDir">目标文件夹</param>
|
|
|
|
|
|
/// <returns>返回复制操作是否成功的标识,成功返回0,负数表示复制失败的文件数量。1表示源文件夹不存在</returns>
|
|
|
|
|
|
public int CopyFolder(string fromDir, string ToDir)
|
|
|
|
|
|
{
|
|
|
|
|
|
return CopyFolder(fromDir,ToDir,0,-1,out _);
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
2023-11-07 08:36:50 +00:00
|
|
|
|
/// 复制文件或文件夹到目标路径,不支持进度事件,支持中途取消
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="fromPath">源路径</param>
|
|
|
|
|
|
/// <param name="ToPath">目标路径</param>
|
|
|
|
|
|
/// <returns>返回复制操作是否成功的标识,成功返回0,负数表示复制失败的文件数量。1表示源文件夹不存在</returns>
|
|
|
|
|
|
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, 0, -1, out _);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
2022-05-26 09:12:39 +00:00
|
|
|
|
/// 复制文件夹到目标文件夹,支持进度事件,支持中途取消
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="fromDir">源文件夹</param>
|
|
|
|
|
|
/// <param name="ToDir">目标文件夹</param>
|
|
|
|
|
|
/// <returns>返回复制操作是否成功的标识,成功返回0,负数表示复制失败的文件数量。1表示源文件夹不存在</returns>
|
|
|
|
|
|
public int CopyFolderByProgress(string fromDir, string ToDir)
|
|
|
|
|
|
{
|
|
|
|
|
|
var FileCount = GetFilesCount(fromDir);
|
|
|
|
|
|
return CopyFolder(fromDir, ToDir, 0, FileCount, out _);
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 复制文件夹到目标文件夹,支持中途取消
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="fromDir">源文件夹</param>
|
|
|
|
|
|
/// <param name="ToDir">目标文件夹</param>
|
|
|
|
|
|
/// <param name="StartCount">初始的文件数量</param>
|
|
|
|
|
|
/// <param name="TotalCount">总数量,如果不计算,则使用-1</param>
|
|
|
|
|
|
/// <param name="Count">操作的数量,包含成功的和失败的</param>
|
|
|
|
|
|
/// <returns>返回复制操作是否成功的标识,成功返回0,负数表示复制失败的文件数量。1表示源文件夹不存在</returns>
|
|
|
|
|
|
private int CopyFolder(string fromDir, string ToDir,int StartCount,int TotalCount, out int Count)
|
|
|
|
|
|
{
|
|
|
|
|
|
Count = StartCount;
|
|
|
|
|
|
var _fromDir = fromDir.TrimEnd('\\');
|
|
|
|
|
|
var _ToDir = ToDir.TrimEnd('\\');
|
|
|
|
|
|
if (!Directory.Exists(_fromDir)) { return 1; }
|
|
|
|
|
|
var files = Directory.GetFiles(fromDir);
|
|
|
|
|
|
var error = 0;
|
|
|
|
|
|
CancelEventArgs e1 = new CancelEventArgs();
|
|
|
|
|
|
foreach (var file in files)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (OnCanel != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
OnCanel?.Invoke(this, e1);
|
|
|
|
|
|
if (e1.Cancel) { break; }
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!CopyBigFile(file, _ToDir + "\\" + Path.GetFileName(file)))
|
|
|
|
|
|
{
|
|
|
|
|
|
error++;
|
|
|
|
|
|
}
|
|
|
|
|
|
Count++;
|
|
|
|
|
|
var percent = 0d;
|
|
|
|
|
|
if (TotalCount>0) { percent = Count / (double)TotalCount; }
|
|
|
|
|
|
else if (TotalCount == -1) { percent = -1; }
|
|
|
|
|
|
OnProgress?.Invoke(Count, TotalCount, percent);
|
|
|
|
|
|
}
|
|
|
|
|
|
var dirs = Directory.GetDirectories(_fromDir);
|
|
|
|
|
|
foreach (var dir in dirs)
|
|
|
|
|
|
{
|
|
|
|
|
|
int result = CopyFolder(dir, _ToDir + "\\" + Path.GetFileName(dir), Count, TotalCount, out var _Count);
|
|
|
|
|
|
Count += _Count;
|
|
|
|
|
|
if (OnCanel != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
OnCanel?.Invoke(this, e1);
|
|
|
|
|
|
if (e1.Cancel) { break; }
|
|
|
|
|
|
}
|
|
|
|
|
|
if (result > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
error++;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (result < 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
error+=-result;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return -error;
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取文件夹中的文件数量
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="Dir">文件夹路径</param>
|
|
|
|
|
|
/// <returns>返回文件数量,中途取消则返回-1</returns>
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取文件夹的大小
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="Dir">文件夹路径</param>
|
|
|
|
|
|
/// <returns>返回文件数量,中途取消则返回-1</returns>
|
|
|
|
|
|
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 +=RyFiles.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;
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 添加文件到指定文件夹,会进行自动重命名,并返回重命名后的文件名(含路径)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="filepath">要添加的文件路径</param>
|
|
|
|
|
|
/// <param name="toFolder">要添加到的文件夹</param>
|
|
|
|
|
|
/// <param name="RenameByTime">是否根据时间进行重命名</param>
|
|
|
|
|
|
/// <param name="OK">返回是否成功执行</param>
|
|
|
|
|
|
/// <returns>成功执行则返回路径,否则返回空</returns>
|
|
|
|
|
|
public string AddFileToFolder(string filepath, string toFolder, bool RenameByTime, out bool OK)
|
|
|
|
|
|
{
|
|
|
|
|
|
OK = false;
|
|
|
|
|
|
var _toFolder = toFolder.TrimEnd('\\');
|
|
|
|
|
|
RyFiles.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 "";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|