多线程,Task,线程安全队列,ConcurrentQueue,ManualResetEventSlim,文件移动
Longforce.FileMove\FileMoveApp\FileMoveApp.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
Longforce.FileMove\FileMoveApp\FileMoveTask.cs
public class FileMoveTask
{
public string SourcePath { get; set; }
public string DestinationPath { get; set; }
}
Longforce.FileMove\FileMoveApp\Program.cs
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
class Program
{
private static readonly string SourceDirectory = @"D:\inetpub\wwwroot\Mes\szaddon\szpH060\HSLPAD";
// @"D:\inetpub\wwwroot\Mes\szaddon\szpH060\HSLPAD";
// @"D:\inetpub\wwwroot\Mes\szaddon\szpH060\Picture";
// @"D:\inetpub\wwwroot\Mes\szaddon\szpH060\OQC_reports";
private static readonly string DestinationDirectory = @"Z:\inetpub\wwwroot\Mes\szaddon\szpH060\HSLPAD";
private static readonly ConcurrentQueue<FileMoveTask> FileMoveQueue = new ConcurrentQueue<FileMoveTask>();
private static readonly CancellationTokenSource CancellationTokenSource = new CancellationTokenSource();
private static readonly ManualResetEventSlim AllFilesProcessed = new ManualResetEventSlim(false);
private static int _totalFiles = 0;
private static int _completedFiles = 0;
private static readonly object _lockObject = new object();
static void Main()
{
Console.WriteLine("开始准备移动文件...");
try
{
// 检查源目录是否存在
if (!Directory.Exists(SourceDirectory))
{
Console.WriteLine($"错误: 源目录 {SourceDirectory} 不存在。");
return;
}
// 创建目标目录(如果不存在)
Directory.CreateDirectory(DestinationDirectory);
// 扫描源目录并准备移动任务
Console.WriteLine("正在扫描文件...");
ScanDirectory(SourceDirectory);
Console.WriteLine($"已扫描完成,共找到 {_totalFiles} 个文件。");
if (_totalFiles == 0)
{
Console.WriteLine("没有文件需要移动。");
return;
}
// 启动进度显示线程
var progressThread = new Thread(ShowProgress);
progressThread.IsBackground = true;
progressThread.Start();
// 启动多个工作线程
const int maxThreads = 8;
var tasks = new Task[maxThreads];
for (int i = 0; i < maxThreads; i++)
{
tasks[i] = Task.Run(() => ProcessFileMoveQueue(CancellationTokenSource.Token));
}
// 等待所有任务完成
Task.WaitAll(tasks);
AllFilesProcessed.Wait();
Console.WriteLine("\n所有文件移动完成!");
}
catch (Exception ex)
{
Console.WriteLine($"\n发生致命错误: {ex.Message}");
}
finally
{
CancellationTokenSource.Cancel();
AllFilesProcessed.Dispose();
}
Console.WriteLine("按任意键退出...");
Console.ReadKey();
}
private static void ScanDirectory(string sourcePath)
{
try
{
// 获取当前目录下的所有文件
string[] files = Directory.GetFiles(sourcePath);
foreach (string file in files)
{
string relativePath = Path.GetRelativePath(SourceDirectory, file);
string destinationPath = Path.Combine(DestinationDirectory, relativePath);
// 创建目标目录(如果不存在)
string destinationDir = Path.GetDirectoryName(destinationPath);
Directory.CreateDirectory(destinationDir);
// 添加到移动队列
FileMoveQueue.Enqueue(new FileMoveTask { SourcePath = file, DestinationPath = destinationPath });
Interlocked.Increment(ref _totalFiles);
}
// 递归处理子目录
string[] directories = Directory.GetDirectories(sourcePath);
foreach (string directory in directories)
{
ScanDirectory(directory);
}
}
catch (Exception ex)
{
Console.WriteLine($"扫描目录时出错 ({sourcePath}): {ex.Message}");
}
}
private static void ProcessFileMoveQueue(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
if (FileMoveQueue.TryDequeue(out FileMoveTask task))
{
try
{
MoveFileWithRetry(task.SourcePath, task.DestinationPath);
Interlocked.Increment(ref _completedFiles);
}
catch (Exception ex)
{
Console.WriteLine($"移动文件时出错 ({task.SourcePath} -> {task.DestinationPath}): {ex.Message}");
}
}
else if (_completedFiles == _totalFiles)
{
AllFilesProcessed.Set();
break;
}
else
{
// 队列暂时为空,等待片刻
Thread.Sleep(100);
}
}
}
private static void MoveFileWithRetry(string sourcePath, string destinationPath, int maxRetries = 3)
{
int retries = 0;
while (true)
{
try
{
// 如果目标文件已存在,删除原来路径的文件
if (File.Exists(destinationPath))
{
File.Delete(sourcePath);
break;
}
// 移动文件
File.Move(sourcePath, destinationPath, false);
// 验证文件是否成功移动
if (!File.Exists(destinationPath))
{
throw new IOException("文件移动后不存在于目标位置");
}
break;
}
catch (Exception ex)
{
retries++;
if (retries > maxRetries)
{
Console.WriteLine($"文件移动失败 ({sourcePath} -> {destinationPath}): {ex.Message}");
throw;
}
// 等待一段时间后重试
Thread.Sleep(500 * retries);
}
}
}
private static void ShowProgress()
{
while (!AllFilesProcessed.IsSet)
{
lock (_lockObject)
{
Console.CursorLeft = 0;
Console.Write($"进度: {_completedFiles}/{_totalFiles} 文件 ({_completedFiles * 100.0 / Math.Max(1, _totalFiles):F2}%)");
}
Thread.Sleep(500);
}
}
}
Longforce.FileMove\.csharpierrc.json
{
"printWidth": 200,
"useTabs": false,
"tabWidth": 4,
"endOfLine": "auto"
}
Longforce.FileMove\global.json
{
"sdk": {
"version": "6.0.427"
}
}
Longforce.FileMove\Longforce.FileMove.sln
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileMoveApp", "FileMoveApp\FileMoveApp.csproj", "{F1B9D848-52A3-4C75-8D86-A13C597AD7A7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F1B9D848-52A3-4C75-8D86-A13C597AD7A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F1B9D848-52A3-4C75-8D86-A13C597AD7A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F1B9D848-52A3-4C75-8D86-A13C597AD7A7}.Debug|x64.ActiveCfg = Debug|Any CPU
{F1B9D848-52A3-4C75-8D86-A13C597AD7A7}.Debug|x64.Build.0 = Debug|Any CPU
{F1B9D848-52A3-4C75-8D86-A13C597AD7A7}.Debug|x86.ActiveCfg = Debug|Any CPU
{F1B9D848-52A3-4C75-8D86-A13C597AD7A7}.Debug|x86.Build.0 = Debug|Any CPU
{F1B9D848-52A3-4C75-8D86-A13C597AD7A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F1B9D848-52A3-4C75-8D86-A13C597AD7A7}.Release|Any CPU.Build.0 = Release|Any CPU
{F1B9D848-52A3-4C75-8D86-A13C597AD7A7}.Release|x64.ActiveCfg = Release|Any CPU
{F1B9D848-52A3-4C75-8D86-A13C597AD7A7}.Release|x64.Build.0 = Release|Any CPU
{F1B9D848-52A3-4C75-8D86-A13C597AD7A7}.Release|x86.ActiveCfg = Release|Any CPU
{F1B9D848-52A3-4C75-8D86-A13C597AD7A7}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
Longforce.FileMove\VERSION.md
```sh
dotnet publish .\FileMoveApp\FileMoveApp.csproj -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true -o .\Publish\FileMoveApp\V1.0.0
dotnet publish .\FileMoveApp\FileMoveApp.csproj -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true -o .\Publish\FileMoveApp\V2.0.0
dotnet publish .\FileMoveApp\FileMoveApp.csproj -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true -o .\Publish\FileMoveApp\V3.0.0