RaUI/Source/MyDb/FileFuns/BigFileOp.cs
zilinsoft 3262955f2f ### 2023-11-07更新
------
#### RaUIV4    V4.0.2311.0701
- *.[全新]整合了MyDb、ryControls、MyDb_MySQL等dll文件到RaUI一个项目。
- *.[新增]新增ApkOp类,可以轻松获取APK信息。
- *.[新增]新增JsonExt扩展类,让Json操作更简单。
- *.[新增]新增WebP类,可以支持webp格式的图片。
- *.[改进]ryQuickSQL中的AddField方法改为自动替换已存在的同名值。
- *.[修复]ryQuickSQL中的AddFieldCalc方法无法正常计算的BUG。
2023-11-07 16:37:53 +08:00

321 lines
14 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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))
{
if (System.IO.File.Exists(targetPath))
{
if (RyFiles.DeleteFile(targetPath) != 0)
{
return false;
}
}
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>
/// 复制文件或文件夹到目标路径,不支持进度事件,支持中途取消
/// </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>
/// 复制文件夹到目标文件夹,支持进度事件,支持中途取消
/// </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 "";
}
}
}
}