多文件上传,文件夹上传,分别从两个按钮上传文件,进度更新会重叠,文件可能重复上传问题解决

dev
洁 任 2025-03-26 11:16:45 +08:00
parent 72b55c79b8
commit e876ccd0d2
2 changed files with 499 additions and 98 deletions

View File

@ -23,7 +23,8 @@
StartValue="1000" /> StartValue="1000" />
</h:Interaction.Behaviors> </h:Interaction.Behaviors>
<Button h:Cattach.Icon="&#xe892;" Command="{Binding UploadCommand}" Content="上传" Style="{DynamicResource {x:Static h:ButtonKeys.Dynamic}}" /> <Button h:Cattach.Icon="&#xe892;" Command="{Binding UploadCommand}" Content="多文件上传" Style="{DynamicResource {x:Static h:ButtonKeys.Dynamic}}" />
<Button h:Cattach.Icon="&#xe892;" Command="{Binding UploadCommand1}" Content="文件夹上传" Style="{DynamicResource {x:Static h:ButtonKeys.Dynamic}}" />
<Button h:Cattach.Icon="&#xe891;" Content="下载" Style="{DynamicResource {x:Static h:ButtonKeys.Dynamic}}" /> <Button h:Cattach.Icon="&#xe891;" Content="下载" Style="{DynamicResource {x:Static h:ButtonKeys.Dynamic}}" />
<Button h:Cattach.Icon="&#xe763;" Content="分享" Style="{DynamicResource {x:Static h:ButtonKeys.Dynamic}}" /> <Button h:Cattach.Icon="&#xe763;" Content="分享" Style="{DynamicResource {x:Static h:ButtonKeys.Dynamic}}" />
<Button h:Cattach.Icon="&#xe643;" Content="删除" Style="{DynamicResource {x:Static h:ButtonKeys.Dynamic}}" /> <Button h:Cattach.Icon="&#xe643;" Content="删除" Style="{DynamicResource {x:Static h:ButtonKeys.Dynamic}}" />

View File

@ -15,6 +15,7 @@ using Hopetry.ViewModel.Send;
using System.IO; using System.IO;
using System.Security.AccessControl; using System.Security.AccessControl;
using System.Diagnostics; using System.Diagnostics;
using Microsoft.WindowsAPICodePack.Dialogs;
namespace HeBianGu.App.Disk namespace HeBianGu.App.Disk
{ {
@ -94,165 +95,564 @@ namespace HeBianGu.App.Disk
} }
#region 文件上传
//private SendViewModel _sendViewModel;
//private IConfiguration config;
//public ICommand UploadCommand { get; }
//public ICommand UploadCommand1 { get; }
//public LoyoutViewModel(SendViewModel sendViewModel, IConfiguration _config)
//{
// _sendViewModel = sendViewModel;
// config = _config;
// UploadCommand = new AsyncRelayCommand(async () => await UploadFile());
// UploadCommand1 = new AsyncRelayCommand(async () => await UploadFile1());
//}
//private SemaphoreSlim _semaphore = new SemaphoreSlim(5);
//private async Task UploadFile()
//{
// var openFileDialog = new Microsoft.Win32.OpenFileDialog();
// openFileDialog.Multiselect = true; // 可选择多个文件
// openFileDialog.Filter = "All Files (*.*)|*.*";
// //openFileDialog.Multiselect = false;
// if (openFileDialog.ShowDialog() == true)
// {
// foreach (string filePath in openFileDialog.FileNames)
// {
// UpLoadItems ut = new UpLoadItems();
// ut.Value = System.IO.Path.GetFileName(filePath);
// ut.Value3 = "等待上传";
// ut.Value5 = filePath;
// ut.Value6 = System.IO.Path.GetFileName(filePath);
// FileInfo fileInfo = new FileInfo(filePath);
// ut.Double1 = fileInfo.Length;
// ut.Double2 = 0.0;
// ut.Bool1 = false;
// if (fileInfo.Exists)
// {
// if (fileInfo.Length < 1024 * 1024)
// {
// ut.Value1 = "0KB/" + Math.Round((double)(fileInfo.Length / 1024), 2).ToString() + "KB";
// }
// else
// {
// ut.Value1 = "0MB/" + Math.Round((double)(fileInfo.Length / (1024 * 1024)), 2).ToString() + "MB";
// }
// }
// _sendViewModel.UpLoadItems.Add(ut);
// }
// //更新总进度
// var timer = new System.Timers.Timer(1000); // 每秒更新一次
// timer.Elapsed += (sender, e) =>
// {
// double currentBytes = _sendViewModel.UpLoadItems.Sum(r=>r.Double2);
// double totalBytes = _sendViewModel.UpLoadItems.Sum(r => r.Double1);
// double speed = Math.Round((currentBytes / totalBytes)*100,0); // KB/s
// _sendViewModel.Progress = speed;
// };
// timer.Start();
// try
// {
// // 创建所有上传任务
// var uploadTasks = _sendViewModel.UpLoadItems.Where(item=>item.Bool1==false)
// .Select(async item =>
// {
// await _semaphore.WaitAsync(); // 等待信号量
// try
// {
// await UploadFileToMinIOWithProgress(item);
// }
// finally
// {
// _semaphore.Release(); // 释放信号量
// }
// })
// .ToList();
// // 等待所有上传任务完成
// await Task.WhenAll(uploadTasks);
// }
// finally
// {
// //更新总进度100%
// _sendViewModel.Progress = 100;
// // 关机
// if (MySetting.Instance.IsOn)
// {
// Shutdown();
// }
// // 停止计时器
// timer.Stop();
// }
// }
//}
//private async Task UploadFileToMinIOWithProgress(UpLoadItems ut)
//{
// // 配置 MinIO 客户端
// IMinioClient client = new Minio.MinioClient()
// .WithEndpoint("123.132.248.154:9107") // MinIO 服务器地址
// .WithCredentials("KcJPKzOsKfVq20EA4Lyh", "HY7K5EkYpRUphEdINZmAq34tsZD3PMLFTnL85y4N") // 访问密钥和密钥
// .Build();
// try
// {
// string bucketName = "test";
// string objectName = System.IO.Path.GetFileName(ut.Value5);
// //var aa = _sendViewModel.UpLoadItems.Where(r => r.Value == objectName).FirstOrDefault();
// //判断桶是否存在
// var beArgs = new BucketExistsArgs().WithBucket(bucketName);
// bool found = await client.BucketExistsAsync(beArgs).ConfigureAwait(false);
// if (!found)
// {
// var mbArgs = new MakeBucketArgs()
// .WithBucket(bucketName);
// await client.MakeBucketAsync(mbArgs).ConfigureAwait(false);
// }
// var progress = new Progress<ProgressReport>(progressReport =>
// {
// // 确保在 UI 线程上更新 Progress
// Application.Current.Dispatcher.Invoke(() =>
// {
// //_sendViewModel.Progress = progressReport.Percentage;
// ut.Int1 = progressReport.Percentage;
// int slashIndex = ut.Value1.IndexOf('/');
// long trans = progressReport.TotalBytesTransferred;
// ut.Double2 = trans;
// if (trans < 1024 * 1024)
// {
// ut.Value1 = Math.Round((double)(trans / 1024), 0).ToString() + "KB" + ut.Value1.Substring(slashIndex);
// }
// else
// {
// ut.Value1 = Math.Round((double)(trans / (1024 * 1024)), 2).ToString() + "MB" + ut.Value1.Substring(slashIndex);
// }
// ut.Value3 = "上传中...";
// });
// });
// PutObjectArgs putObjectArgs = new PutObjectArgs()
// .WithBucket(bucketName)
// .WithObject(ut.Value6)
// .WithFileName(ut.Value5)
// //.WithContentType("application/octet-stream")
// .WithProgress(progress);
// // 上传文件并提供进度反馈
// await client.PutObjectAsync(putObjectArgs);
// ut.Value3 = "已完成";
// ut.Bool1 = true;
// //MessageBox.Show("文件上传成功!");
// }
// catch (Exception ex)
// {
// MessageBox.Show($"上传失败: {ex.Message}");
// }
//}
////文件夹上传
//private async Task UploadFile1()
//{
// var dialog = new CommonOpenFileDialog
// {
// IsFolderPicker = true,
// Title = "请选择上传文件"
// };
// if (dialog.ShowDialog() == CommonFileDialogResult.Ok)
// {
// string folderPath = dialog.FileName;
// var files = Directory.GetFiles(folderPath, "*.*", SearchOption.AllDirectories);
// foreach (string filePath in files)
// {
// UpLoadItems ut = new UpLoadItems();
// ut.Value = System.IO.Path.GetFileName(filePath);
// ut.Value3 = "等待上传";
// ut.Value5 = filePath;
// ut.Value6= filePath.Substring(folderPath.Length + 1).Replace('\\', '/');
// ;
// FileInfo fileInfo = new FileInfo(filePath);
// ut.Double1 = fileInfo.Length;
// ut.Double2 = 0.0;
// if (fileInfo.Exists)
// {
// if (fileInfo.Length < 1024 * 1024)
// {
// ut.Value1 = "0KB/" + Math.Round((double)(fileInfo.Length / 1024), 2).ToString() + "KB";
// }
// else
// {
// ut.Value1 = "0MB/" + Math.Round((double)(fileInfo.Length / (1024 * 1024)), 2).ToString() + "MB";
// }
// }
// _sendViewModel.UpLoadItems.Add(ut);
// }
// //更新总进度
// var timer = new System.Timers.Timer(1000); // 每秒更新一次
// timer.Elapsed += (sender, e) =>
// {
// double currentBytes = _sendViewModel.UpLoadItems.Sum(r => r.Double2);
// double totalBytes = _sendViewModel.UpLoadItems.Sum(r => r.Double1);
// double speed = Math.Round((currentBytes / totalBytes) * 100, 0); // KB/s
// _sendViewModel.Progress = speed;
// };
// timer.Start();
// try
// {
// // 创建所有上传任务
// var uploadTasks = _sendViewModel.UpLoadItems.Where(item => item.Bool1 == false)
// .Select(async item =>
// {
// await _semaphore.WaitAsync(); // 等待信号量
// try
// {
// await UploadFileToMinIOWithProgress(item);
// }
// finally
// {
// _semaphore.Release(); // 释放信号量
// }
// })
// .ToList();
// // 等待所有上传任务完成
// await Task.WhenAll(uploadTasks);
// }
// finally
// {
// //更新总进度100%
// _sendViewModel.Progress = 100;
// // 关机
// if (MySetting.Instance.IsOn)
// {
// Shutdown();
// }
// // 停止计时器
// timer.Stop();
// }
// }
//}
//// 关机方法
//private void Shutdown()
//{
// try
// {
// // 使用shutdown命令关机
// Process.Start("shutdown", "/s /t 0");
// }
// catch (System.ComponentModel.Win32Exception ex)
// {
// MessageBox.Show($"关机失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
// }
//}
#endregion
#region 文件上传 #region 文件上传
private SendViewModel _sendViewModel; private SendViewModel _sendViewModel;
private IConfiguration config; private IConfiguration config;
private SemaphoreSlim _semaphore = new SemaphoreSlim(5);
private System.Timers.Timer _progressTimer;
private bool _isTimerRunning = false;
private object _timerLock = new object();
private bool _isUploading = false; // 新增:标记是否有上传任务正在运行
private Task _currentUploadTask = null; // 新增:当前上传任务
private CancellationTokenSource _uploadCancellation = new CancellationTokenSource();
public ICommand UploadCommand { get; } public ICommand UploadCommand { get; }
public LoyoutViewModel(SendViewModel sendViewModel, IConfiguration _config) public ICommand UploadCommand1 { get; }
public LoyoutViewModel(SendViewModel sendViewModel)
{ {
_sendViewModel = sendViewModel; _sendViewModel = sendViewModel;
config = _config;
UploadCommand = new AsyncRelayCommand(async () => await UploadFile()); UploadCommand = new AsyncRelayCommand(async () => await UploadFile());
UploadCommand1 = new AsyncRelayCommand(async () => await UploadFile1());
// 初始化Timer
_progressTimer = new System.Timers.Timer(1000);
_progressTimer.Elapsed += UpdateProgress;
}
private void UpdateProgress(object sender, System.Timers.ElapsedEventArgs e)
{
lock (_timerLock)
{
if (_sendViewModel.UpLoadItems.Count == 0) return;
double currentBytes = _sendViewModel.UpLoadItems.Sum(r => r.Double2);
double totalBytes = _sendViewModel.UpLoadItems.Sum(r => r.Double1);
double progress = Math.Round((currentBytes / totalBytes) * 100, 0);
Application.Current.Dispatcher.Invoke(() =>
{
_sendViewModel.Progress = progress;
});
}
}
private void StartProgressTimer()
{
lock (_timerLock)
{
if (!_isTimerRunning)
{
_progressTimer.Start();
_isTimerRunning = true;
}
}
}
private void StopProgressTimer()
{
lock (_timerLock)
{
if (_isTimerRunning)
{
_progressTimer.Stop();
_isTimerRunning = false;
}
}
} }
private SemaphoreSlim _semaphore = new SemaphoreSlim(5);
private async Task UploadFile() private async Task UploadFile()
{ {
_sendViewModel.UpLoadItems.Clear(); var openFileDialog = new Microsoft.Win32.OpenFileDialog
var openFileDialog = new Microsoft.Win32.OpenFileDialog(); {
Multiselect = true,
openFileDialog.Multiselect = true; // 可选择多个文件 Filter = "All Files (*.*)|*.*"
openFileDialog.Filter = "All Files (*.*)|*.*"; };
//openFileDialog.Multiselect = false;
if (openFileDialog.ShowDialog() == true) if (openFileDialog.ShowDialog() == true)
{ {
foreach (string filePath in openFileDialog.FileNames) // 过滤掉已经存在的文件
var newFiles = openFileDialog.FileNames
.Where(filePath => !_sendViewModel.UpLoadItems.Any(item =>
item.Value5.Equals(filePath, StringComparison.OrdinalIgnoreCase)))
.ToList();
if (newFiles.Count == 0)
{ {
UpLoadItems ut = new UpLoadItems(); MessageBox.Show("没有新文件需要上传或文件已在上传队列中");
ut.Value = System.IO.Path.GetFileName(filePath); return;
ut.Value3 = "等待上传";
ut.Value5 = filePath;
FileInfo fileInfo = new FileInfo(filePath);
ut.Double1 = fileInfo.Length;
ut.Double2 = 0.0;
if (fileInfo.Exists)
{
if (fileInfo.Length < 1024 * 1024)
{
ut.Value1 = "0KB/" + Math.Round((double)(fileInfo.Length / 1024), 2).ToString() + "KB";
} }
else
foreach (string filePath in newFiles)
{ {
ut.Value1 = "0MB/" + Math.Round((double)(fileInfo.Length / (1024 * 1024)), 2).ToString() + "MB"; var ut = CreateUploadItem(filePath, System.IO.Path.GetFileName(filePath));
}
}
_sendViewModel.UpLoadItems.Add(ut); _sendViewModel.UpLoadItems.Add(ut);
} }
//更新总进度
var timer = new System.Timers.Timer(1000); // 每秒更新一次 // 如果没有上传任务在运行,则启动上传
timer.Elapsed += (sender, e) => if (!_isUploading)
{ {
double currentBytes = _sendViewModel.UpLoadItems.Sum(r=>r.Double2); await ProcessUploadTasks();
double totalBytes = _sendViewModel.UpLoadItems.Sum(r => r.Double1); }
double speed = Math.Round((currentBytes / totalBytes)*100,0); // KB/s }
_sendViewModel.Progress = speed; }
private async Task UploadFile1()
{
var dialog = new CommonOpenFileDialog
{
IsFolderPicker = true,
Title = "请选择上传文件"
}; };
timer.Start();
if (dialog.ShowDialog() == CommonFileDialogResult.Ok)
{
string folderPath = dialog.FileName;
var files = Directory.GetFiles(folderPath, "*.*", SearchOption.AllDirectories)
.Where(filePath => !_sendViewModel.UpLoadItems.Any(item =>
item.Value5.Equals(filePath, StringComparison.OrdinalIgnoreCase)))
.ToList();
if (files.Count == 0)
{
MessageBox.Show("没有新文件需要上传或文件已在上传队列中");
return;
}
foreach (string filePath in files)
{
string relativePath = filePath.Substring(folderPath.Length + 1).Replace('\\', '/');
var ut = CreateUploadItem(filePath, relativePath);
_sendViewModel.UpLoadItems.Add(ut);
}
// 如果没有上传任务在运行,则启动上传
if (!_isUploading)
{
await ProcessUploadTasks();
}
}
}
private UpLoadItems CreateUploadItem(string filePath, string objectName)
{
FileInfo fileInfo = new FileInfo(filePath);
string sizeText = fileInfo.Length < 1024 * 1024 ?
$"{Math.Round((double)(fileInfo.Length / 1024), 2)}KB" :
$"{Math.Round((double)(fileInfo.Length / (1024 * 1024)), 2)}MB";
return new UpLoadItems
{
Value = System.IO.Path.GetFileName(filePath),
Value3 = "等待上传",
Value5 = filePath,
Value6 = objectName,
Double1 = fileInfo.Length,
Double2 = 0.0,
Bool1 = false,
Value1 = $"0{(fileInfo.Length < 1024 * 1024 ? "KB" : "MB")}/{sizeText}"
};
}
private async Task ProcessUploadTasks()
{
_isUploading = true;
StartProgressTimer();
try try
{ {
// 创建所有上传任务 while (true)
var uploadTasks = _sendViewModel.UpLoadItems
.Select(async item =>
{ {
await _semaphore.WaitAsync(); // 等待信号量 // 获取所有未完成的上传项
var pendingItems = _sendViewModel.UpLoadItems
.Where(item => !item.Bool1)
.ToList();
if (!pendingItems.Any())
break; // 没有待上传文件,退出循环
// 创建并运行上传任务
_currentUploadTask = Task.WhenAll(pendingItems.Select(async item =>
{
await _semaphore.WaitAsync(_uploadCancellation.Token);
try try
{ {
await UploadFileToMinIOWithProgress(item); await UploadFileToMinIOWithProgress(item);
} }
finally finally
{ {
_semaphore.Release(); // 释放信号量 _semaphore.Release();
} }
}) }));
.ToList();
// 等待所有上传任务完成 await _currentUploadTask;
await Task.WhenAll(uploadTasks); }
}
catch (OperationCanceledException)
{
// 上传被取消
} }
finally finally
{ {
//更新总进度100% StopProgressTimer();
Application.Current.Dispatcher.Invoke(() =>
{
_sendViewModel.Progress = 100; _sendViewModel.Progress = 100;
// 关机 });
if (MySetting.Instance.IsOn) _isUploading = false;
if (MySetting.Instance.IsOn && !_sendViewModel.UpLoadItems.Any(item => !item.Bool1))
{ {
Shutdown(); Shutdown();
} }
// 停止计时器
timer.Stop();
}
} }
} }
private async Task UploadFileToMinIOWithProgress(UpLoadItems ut) private async Task UploadFileToMinIOWithProgress(UpLoadItems ut)
{ {
// 配置 MinIO 客户端 ut.Bool1 = true;
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("global.json", optional: false, reloadOnChange: true);
// 构建配置
var config = builder.Build();
// 从配置获取MinIO设置更安全
IMinioClient client = new Minio.MinioClient() IMinioClient client = new Minio.MinioClient()
.WithEndpoint("123.132.248.154:9107") // MinIO 服务器地址 .WithEndpoint(config["Minio:Endpoint"])
.WithCredentials("KcJPKzOsKfVq20EA4Lyh", "HY7K5EkYpRUphEdINZmAq34tsZD3PMLFTnL85y4N") // 访问密钥和密钥 .WithCredentials(config["Minio:AccessKey"], config["Minio:SecretKey"])
.Build(); .Build();
try try
{ {
string bucketName = "test"; string bucketName = "test";
string objectName = System.IO.Path.GetFileName(ut.Value5);
//var aa = _sendViewModel.UpLoadItems.Where(r => r.Value == objectName).FirstOrDefault(); //// 检查文件是否已存在
//判断桶是否存在 //var statArgs = new StatObjectArgs()
// .WithBucket(bucketName)
// .WithObject(ut.Value6);
//try
//{
// await client.StatObjectAsync(statArgs);
// // 文件已存在,跳过上传
// ut.Value3 = "已存在";
// ut.Bool1 = true;
// ut.Double2 = ut.Double1; // 设置已传输大小为总大小
// return;
//}
//catch (Exception)
//{
// // 文件不存在,继续上传
//}
// 确保桶存在
var beArgs = new BucketExistsArgs().WithBucket(bucketName); var beArgs = new BucketExistsArgs().WithBucket(bucketName);
bool found = await client.BucketExistsAsync(beArgs).ConfigureAwait(false); bool found = await client.BucketExistsAsync(beArgs).ConfigureAwait(false);
if (!found) if (!found)
{ {
var mbArgs = new MakeBucketArgs() var mbArgs = new MakeBucketArgs().WithBucket(bucketName);
.WithBucket(bucketName);
await client.MakeBucketAsync(mbArgs).ConfigureAwait(false); await client.MakeBucketAsync(mbArgs).ConfigureAwait(false);
} }
var progress = new Progress<ProgressReport>(progressReport => var progress = new Progress<ProgressReport>(progressReport =>
{ {
// 确保在 UI 线程上更新 Progress
Application.Current.Dispatcher.Invoke(() => Application.Current.Dispatcher.Invoke(() =>
{ {
//_sendViewModel.Progress = progressReport.Percentage;
ut.Int1 = progressReport.Percentage; ut.Int1 = progressReport.Percentage;
int slashIndex = ut.Value1.IndexOf('/');
long trans = progressReport.TotalBytesTransferred; long trans = progressReport.TotalBytesTransferred;
ut.Double2 = trans; ut.Double2 = trans;
if (trans < 1024 * 1024)
{ int slashIndex = ut.Value1.IndexOf('/');
ut.Value1 = Math.Round((double)(trans / 1024), 0).ToString() + "KB" + ut.Value1.Substring(slashIndex); string sizePart = ut.Value1.Substring(slashIndex);
} string transferredPart = trans < 1024 * 1024 ?
else $"{Math.Round((double)(trans / 1024), 0)}KB" :
{ $"{Math.Round((double)(trans / (1024 * 1024)), 2)}MB";
ut.Value1 = Math.Round((double)(trans / (1024 * 1024)), 2).ToString() + "MB" + ut.Value1.Substring(slashIndex);
} ut.Value1 = $"{transferredPart}{sizePart}";
ut.Value3 = "上传中..."; ut.Value3 = "上传中...";
}); });
}); });
PutObjectArgs putObjectArgs = new PutObjectArgs() var putObjectArgs = new PutObjectArgs()
.WithBucket(bucketName) .WithBucket(bucketName)
.WithObject(objectName) .WithObject(ut.Value6)
.WithFileName(ut.Value5) .WithFileName(ut.Value5)
//.WithContentType("application/octet-stream")
.WithProgress(progress); .WithProgress(progress);
// 上传文件并提供进度反馈
await client.PutObjectAsync(putObjectArgs); await client.PutObjectAsync(putObjectArgs);
ut.Value3 = "已完成"; ut.Value3 = "已完成";
//MessageBox.Show("文件上传成功!");
} }
catch (Exception ex) catch (Exception ex)
{ {
MessageBox.Show($"上传失败: {ex.Message}"); Application.Current.Dispatcher.Invoke(() =>
{
ut.Value3 = $"上传失败: {ex.Message}";
});
} }
} }
// 关机方法
private void Shutdown() private void Shutdown()
{ {
try try
{ {
// 使用shutdown命令关机
Process.Start("shutdown", "/s /t 0"); Process.Start("shutdown", "/s /t 0");
} }
catch (System.ComponentModel.Win32Exception ex) catch (System.ComponentModel.Win32Exception ex)