
在C#开发中,文件操作是基础中的基础,但有时最基础的File.Copy()方法也会抛出令人困惑的异常。最近我遇到了这样一个问题:
File.Copy(sourceFile, targetFilePath);当targetFilePath设置为D:\25Q1\MR3.6.6.1_C1.2.37_PB250623\bin\gc_data时,系统抛出"未能找到文件"的异常。令人困惑的是,bin目录确定存在,gc_data是目标文件名而非目录名,源文件也存在。本文将深入分析这个问题的原因,并提供全面的解决方案。
if (File.Exists(sourceFile))
{
File.Copy(sourceFile, targetFilePath);
}
else
{
// 显示源文件不存在的错误
}未能找到文件“D:\25Q1\MR3.6.6.1_C1.2.37_PB250623\bin\gc_data”bin目录存在,但路径中的上级目录可能缺失string targetDir = Path.GetDirectoryName(targetFilePath);
// 递归创建所有缺失的目录
if (!Directory.Exists(targetDir))
{
try
{
Directory.CreateDirectory(targetDir);
Console.WriteLine($"创建目录: {targetDir}");
}
catch (Exception ex)
{
Console.WriteLine($"目录创建失败: {ex.Message}");
// 处理目录创建失败
}
}public static bool CopyFileWithRetry(string source, string destination, int maxRetries = 3, int delay = 500)
{
for (int i = 0; i < maxRetries; i++)
{
try
{
File.Copy(source, destination, overwrite: true);
return true;
}
catch (IOException) when (i < maxRetries - 1)
{
// 文件可能被锁定,等待后重试
Thread.Sleep(delay);
// 可选:尝试解锁文件
TryReleaseFileLock(destination);
}
catch (UnauthorizedAccessException)
{
// 权限问题处理
Console.WriteLine($"权限不足: {destination}");
break;
}
}
return false;
}
private static void TryReleaseFileLock(string filePath)
{
// 尝试关闭可能锁定文件的资源管理器进程
var processes = FileUtil.WhoIsLocking(filePath);
foreach (var process in processes)
{
if (process.ProcessName.Equals("explorer"))
{
// 优雅地关闭资源管理器预览
WindowsAPI.CloseExplorerPreview();
}
}
}<!-- 在app.config中启用长路径支持 -->
<runtime>
<AppContextSwitchOverrides
value="Switch.System.IO.UseLegacyPathHandling=false;
Switch.System.IO.BlockLongPaths=false" />
</runtime>// 使用UNC路径处理超长路径
if (targetFilePath.Length > 240)
{
targetFilePath = @"\\?\" + targetFilePath;
}using System.Diagnostics;
using System.Management;
using System.Runtime.InteropServices;
public static class FileUtil
{
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
const uint WM_CLOSE = 0x0010;
public static void CloseExplorerPreview()
{
IntPtr hWnd = FindWindow("CabinetWClass", null);
if (hWnd != IntPtr.Zero)
{
SendMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
}
}
public static List<Process> WhoIsLocking(string path)
{
var processes = new List<Process>();
var filePath = Path.GetFullPath(path).ToLower();
using var searcher = new ManagementObjectSearcher(
"SELECT * FROM Win32_Process WHERE ExecutablePath IS NOT NULL");
foreach (ManagementObject process in searcher.Get())
{
try
{
string[] commandLines = (string[])process["CommandLine"];
foreach (string cmdLine in commandLines ?? Array.Empty<string>())
{
if (cmdLine != null && cmdLine.ToLower().Contains(filePath))
{
int pid = Convert.ToInt32(process["ProcessId"]);
processes.Add(Process.GetProcessById(pid));
}
}
}
catch
{
// 忽略无法访问的进程
}
}
return processes;
}
}public static bool HasWritePermission(string folderPath)
{
try
{
string testFile = Path.Combine(folderPath, "permission_test.tmp");
File.WriteAllText(testFile, "test");
File.Delete(testFile);
return true;
}
catch
{
return false;
}
}
public static void RequestAdminPrivileges()
{
var processInfo = new ProcessStartInfo
{
FileName = Assembly.GetExecutingAssembly().Location,
UseShellExecute = true,
Verb = "runas" // 请求管理员权限
};
try
{
Process.Start(processInfo);
Environment.Exit(0);
}
catch
{
// 用户拒绝权限请求
}
}public static void SafeFileCopy(string sourceFile, string targetFilePath)
{
// 验证源文件
if (!File.Exists(sourceFile))
{
ShowError($"源文件不存在: {sourceFile}");
return;
}
// 处理长路径
if (targetFilePath.Length > 240 && !targetFilePath.StartsWith(@"\\?\"))
{
targetFilePath = @"\\?\" + targetFilePath;
}
// 确保目标目录存在
string targetDir = Path.GetDirectoryName(targetFilePath);
if (!Directory.Exists(targetDir))
{
try
{
Directory.CreateDirectory(targetDir);
}
catch (Exception ex)
{
ShowError($"目录创建失败: {ex.Message}");
return;
}
}
// 检查写入权限
if (!HasWritePermission(targetDir))
{
ShowError($"没有写入权限: {targetDir}");
RequestAdminPrivileges();
return;
}
// 尝试复制文件(带重试)
if (!CopyFileWithRetry(sourceFile, targetFilePath))
{
// 诊断文件锁定问题
var lockingProcesses = FileUtil.WhoIsLocking(targetFilePath);
if (lockingProcesses.Count > 0)
{
string processList = string.Join("\n",
lockingProcesses.Select(p => $"{p.ProcessName} (PID: {p.Id})"));
ShowError($"文件被以下进程锁定:\n{processList}");
}
else
{
ShowError($"文件复制失败,原因未知: {targetFilePath}");
}
}
}Path.Combine()构建路径Path.GetFullPath()规范化路径文件复制操作看似简单,但在实际企业级应用中需要考虑多种边界情况和异常处理。通过本文的解决方案,我们可以:
关键解决方案要点:
在实际应用中,建议将这些文件操作方法封装为公共工具类,确保整个项目遵循统一的文件操作标准,从而显著提高应用程序的稳定性和用户体验。
经验分享:在文件操作相关代码中,花30%的时间处理主逻辑,70%的时间处理边界情况和异常,往往是值得的投资。稳定的文件操作是应用程序可靠性的基石之一。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。