System.IO.DirectoryNotFoundException 在 File.Delete 上的有效路径
System.IO.DirectoryNotFoundException on File.Delete for a valid path
我编写代码以递归方式删除一个文件夹及其所有结构。
我在 File.Delete
上得到了 System.IO.DirectoryNotFoundException
,因为我从 Directory.GetFiles(path)
得到了一个有效的文件名。我之前添加了 File.Exists
,它告诉我该文件不存在,我可以在资源管理器中看到它。
我知道我可以用 SHFileOperation
做到这一点,应该可以正常工作。但是我想用原生的C#(没有直接WindowsAPI)。
我红色:.NET 4.6.2 and long paths on Windows 10 并在本地组策略编辑器中设置启用 "Enable Win 32 long paths"。
我正在使用 .NET Framework 4.7.2。
有谁能告诉我我的代码有什么问题吗?或者我可以做些什么来让它发挥作用?
错误的路径是:
'E:\CobianBackupOld\cn1629\AppData\Local\Packages\Microsoft.Windows.Cortana_cw5n1h2txyewy\LocalState\AppIconCache0\{7C5A40EF-A0FB-4BFC-874A-C0F2E0B9FA8E}_Microsoft Visual Studio 9_0_Application_PreEmptive Solutions_Dotfuscator Community Edition_dotfuscator_exe'
我是该文件的所有者(我有权删除它)。
UPDATE
I partly fixed my error but would like to know how to fix it properly (Recent frameworks are suppose to support long path???).
My actual fix is to add that code at start of my recursice function
if (path.Length < 2 || !path.StartsWith(@"\"))
{
path = @"\?\" + path;
}
UPDATE 2 Although not directly related... Just want to bring an important point, C# File.Delete or Directory.Delete does NOT delete
readonly file or folder, you should also change their permissions to
normal before deleting them, otherwise you get an access denied error.
仅供参考,我的代码是:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HQ.Util.General.IO
{
public class DirectoryRemoverRecursive
{
private readonly Action<string, string> _pathStatus;
private readonly Func<string, bool> _callbackCanRemoveFile;
private readonly Func<string, bool> _callbackCanRemoveFolder;
private Func<bool> _shouldCancel;
/// <summary>
///
/// </summary>
/// <param name="pathStatus">Arguments are [path] and [null on success or exception message]</param>
/// <param name="callbackCanRemoveFile">Argument is path and should return true to delete. If this function is null, all path will be deleted.</param>
/// <param name="callbackCanRemoveFolder">Argument is path and should return true to delete. If this function is null, all path will be deleted.</param>
/// <param name="shouldCancel">If null will never cancel. Cancel when func return true</param>
public DirectoryRemoverRecursive(
Action<string, string> pathStatus = null,
Func<string, bool> callbackCanRemoveFile = null,
Func<string, bool> callbackCanRemoveFolder = null,
Func<bool> shouldCancel = null)
{
_pathStatus = pathStatus;
_callbackCanRemoveFile = callbackCanRemoveFile;
_callbackCanRemoveFolder = callbackCanRemoveFolder;
_shouldCancel = shouldCancel;
}
// ******************************************************************
/// <summary>
/// return true if canceled
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public bool Remove(string path)
{
string result = null;
if (Directory.Exists(path))
{
foreach (var subDir in Directory.GetDirectories(path))
{
if (_shouldCancel != null)
{
if (_shouldCancel())
{
return true;
}
}
if (Remove(subDir))
{
return true;
}
}
foreach (var filename in Directory.GetFiles(path))
{
if (_shouldCancel != null)
{
if (_shouldCancel())
{
return true;
}
}
if (Remove(filename))
{
return true;
}
}
try
{
if (_callbackCanRemoveFolder != null)
{
if (!_callbackCanRemoveFolder(path))
{
return false;
}
}
Directory.Delete(path);
result = null;
}
catch (Exception ex)
{
result = ex.Message;
}
}
else
{
try
{
if (File.Exists(path))
{
if (_callbackCanRemoveFile != null)
{
if (!_callbackCanRemoveFile(path))
{
return false;
}
}
File.Delete(path);
result = null;
}
else
{
Debug.Print($"File does not exists {path}");
}
}
catch (Exception ex)
{
result = ex.Message;
}
}
_pathStatus?.Invoke(path, result);
return false;
}
// ******************************************************************
}
}
虽然没有我希望的那么完美,但我通过使用前缀“\?\”并确保在删除之前将属性设置为正常来修复了我的错误。
我还是不明白为什么我还是要那样做???为什么它在最近的 .net 库中仍未修复?
最终代码:
using System;
using System.Diagnostics;
using System.IO;
namespace HQ.Util.General.IO
{
public class DirectoryRemoverRecursive
{
private readonly Action<string, string, int> _pathStatus;
private readonly Func<string, bool> _callbackCanRemoveFile;
private readonly Func<string, bool> _callbackCanRemoveFolder;
private Func<bool> _shouldCancel;
public int Count { get; private set; } = 0;
/// <summary>
///
/// </summary>
/// <param name="pathStatus">Arguments are [path] and [null on success or exception message]</param>
/// <param name="callbackCanRemoveFile">Argument is path and should return true to delete. If this function is null, all path will be deleted.</param>
/// <param name="callbackCanRemoveFolder">Argument is path and should return true to delete. If this function is null, all path will be deleted.</param>
/// <param name="shouldCancel">If null will never cancel. Cancel when func return true</param>
public DirectoryRemoverRecursive(
Action<string, string, int> pathStatus = null,
Func<string, bool> callbackCanRemoveFile = null,
Func<string, bool> callbackCanRemoveFolder = null,
Func<bool> shouldCancel = null)
{
_pathStatus = pathStatus;
_callbackCanRemoveFile = callbackCanRemoveFile;
_callbackCanRemoveFolder = callbackCanRemoveFolder;
_shouldCancel = shouldCancel;
}
// ******************************************************************
/// <summary>
/// return true if canceled
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public bool Remove(string path)
{
string result = null;
if (path.Length < 2 || !path.StartsWith(@"\"))
{
path = @"\?\" + path;
}
if (Directory.Exists(path))
{
foreach (var subDir in Directory.GetDirectories(path))
{
if (_shouldCancel != null)
{
if (_shouldCancel())
{
return true;
}
}
if (Remove(subDir))
{
return true;
}
}
foreach (var filename in Directory.GetFiles(path))
{
if (_shouldCancel != null)
{
if (_shouldCancel())
{
return true;
}
}
if (Remove(filename))
{
return true;
}
}
try
{
if (_callbackCanRemoveFolder != null)
{
if (!_callbackCanRemoveFolder(path))
{
return false;
}
}
Directory.Delete(path);
Count++;
result = null;
}
catch (Exception ex)
{
try
{
File.SetAttributes(path, FileAttributes.Normal);
Directory.Delete(path);
Count++;
result = null;
}
catch (Exception)
{
result = "Try to delete directory exception: " + ex.ToString();
}
}
}
else
{
try
{
if (File.Exists(path))
{
if (_callbackCanRemoveFile != null)
{
if (!_callbackCanRemoveFile(path))
{
return false;
}
}
File.Delete(path);
Count++;
result = null;
}
else
{
Debug.Print($"File does not exists {path}");
}
}
catch (Exception ex)
{
try
{
File.SetAttributes(path, FileAttributes.Normal);
File.Delete(path);
Count++;
result = null;
}
catch (Exception)
{
result = "Try to delete file exception: " + ex.ToString();
}
}
}
_pathStatus?.Invoke(path, result, Count);
return false;
}
// ******************************************************************
}
}
我编写代码以递归方式删除一个文件夹及其所有结构。
我在 File.Delete
上得到了 System.IO.DirectoryNotFoundException
,因为我从 Directory.GetFiles(path)
得到了一个有效的文件名。我之前添加了 File.Exists
,它告诉我该文件不存在,我可以在资源管理器中看到它。
我知道我可以用 SHFileOperation
做到这一点,应该可以正常工作。但是我想用原生的C#(没有直接WindowsAPI)。
我红色:.NET 4.6.2 and long paths on Windows 10 并在本地组策略编辑器中设置启用 "Enable Win 32 long paths"。
我正在使用 .NET Framework 4.7.2。
有谁能告诉我我的代码有什么问题吗?或者我可以做些什么来让它发挥作用?
错误的路径是:
'E:\CobianBackupOld\cn1629\AppData\Local\Packages\Microsoft.Windows.Cortana_cw5n1h2txyewy\LocalState\AppIconCache0\{7C5A40EF-A0FB-4BFC-874A-C0F2E0B9FA8E}_Microsoft Visual Studio 9_0_Application_PreEmptive Solutions_Dotfuscator Community Edition_dotfuscator_exe'
我是该文件的所有者(我有权删除它)。
UPDATE
I partly fixed my error but would like to know how to fix it properly (Recent frameworks are suppose to support long path???). My actual fix is to add that code at start of my recursice function
if (path.Length < 2 || !path.StartsWith(@"\")) { path = @"\?\" + path; }
UPDATE 2 Although not directly related... Just want to bring an important point, C# File.Delete or Directory.Delete does NOT delete readonly file or folder, you should also change their permissions to normal before deleting them, otherwise you get an access denied error.
仅供参考,我的代码是:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HQ.Util.General.IO
{
public class DirectoryRemoverRecursive
{
private readonly Action<string, string> _pathStatus;
private readonly Func<string, bool> _callbackCanRemoveFile;
private readonly Func<string, bool> _callbackCanRemoveFolder;
private Func<bool> _shouldCancel;
/// <summary>
///
/// </summary>
/// <param name="pathStatus">Arguments are [path] and [null on success or exception message]</param>
/// <param name="callbackCanRemoveFile">Argument is path and should return true to delete. If this function is null, all path will be deleted.</param>
/// <param name="callbackCanRemoveFolder">Argument is path and should return true to delete. If this function is null, all path will be deleted.</param>
/// <param name="shouldCancel">If null will never cancel. Cancel when func return true</param>
public DirectoryRemoverRecursive(
Action<string, string> pathStatus = null,
Func<string, bool> callbackCanRemoveFile = null,
Func<string, bool> callbackCanRemoveFolder = null,
Func<bool> shouldCancel = null)
{
_pathStatus = pathStatus;
_callbackCanRemoveFile = callbackCanRemoveFile;
_callbackCanRemoveFolder = callbackCanRemoveFolder;
_shouldCancel = shouldCancel;
}
// ******************************************************************
/// <summary>
/// return true if canceled
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public bool Remove(string path)
{
string result = null;
if (Directory.Exists(path))
{
foreach (var subDir in Directory.GetDirectories(path))
{
if (_shouldCancel != null)
{
if (_shouldCancel())
{
return true;
}
}
if (Remove(subDir))
{
return true;
}
}
foreach (var filename in Directory.GetFiles(path))
{
if (_shouldCancel != null)
{
if (_shouldCancel())
{
return true;
}
}
if (Remove(filename))
{
return true;
}
}
try
{
if (_callbackCanRemoveFolder != null)
{
if (!_callbackCanRemoveFolder(path))
{
return false;
}
}
Directory.Delete(path);
result = null;
}
catch (Exception ex)
{
result = ex.Message;
}
}
else
{
try
{
if (File.Exists(path))
{
if (_callbackCanRemoveFile != null)
{
if (!_callbackCanRemoveFile(path))
{
return false;
}
}
File.Delete(path);
result = null;
}
else
{
Debug.Print($"File does not exists {path}");
}
}
catch (Exception ex)
{
result = ex.Message;
}
}
_pathStatus?.Invoke(path, result);
return false;
}
// ******************************************************************
}
}
虽然没有我希望的那么完美,但我通过使用前缀“\?\”并确保在删除之前将属性设置为正常来修复了我的错误。
我还是不明白为什么我还是要那样做???为什么它在最近的 .net 库中仍未修复?
最终代码:
using System;
using System.Diagnostics;
using System.IO;
namespace HQ.Util.General.IO
{
public class DirectoryRemoverRecursive
{
private readonly Action<string, string, int> _pathStatus;
private readonly Func<string, bool> _callbackCanRemoveFile;
private readonly Func<string, bool> _callbackCanRemoveFolder;
private Func<bool> _shouldCancel;
public int Count { get; private set; } = 0;
/// <summary>
///
/// </summary>
/// <param name="pathStatus">Arguments are [path] and [null on success or exception message]</param>
/// <param name="callbackCanRemoveFile">Argument is path and should return true to delete. If this function is null, all path will be deleted.</param>
/// <param name="callbackCanRemoveFolder">Argument is path and should return true to delete. If this function is null, all path will be deleted.</param>
/// <param name="shouldCancel">If null will never cancel. Cancel when func return true</param>
public DirectoryRemoverRecursive(
Action<string, string, int> pathStatus = null,
Func<string, bool> callbackCanRemoveFile = null,
Func<string, bool> callbackCanRemoveFolder = null,
Func<bool> shouldCancel = null)
{
_pathStatus = pathStatus;
_callbackCanRemoveFile = callbackCanRemoveFile;
_callbackCanRemoveFolder = callbackCanRemoveFolder;
_shouldCancel = shouldCancel;
}
// ******************************************************************
/// <summary>
/// return true if canceled
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public bool Remove(string path)
{
string result = null;
if (path.Length < 2 || !path.StartsWith(@"\"))
{
path = @"\?\" + path;
}
if (Directory.Exists(path))
{
foreach (var subDir in Directory.GetDirectories(path))
{
if (_shouldCancel != null)
{
if (_shouldCancel())
{
return true;
}
}
if (Remove(subDir))
{
return true;
}
}
foreach (var filename in Directory.GetFiles(path))
{
if (_shouldCancel != null)
{
if (_shouldCancel())
{
return true;
}
}
if (Remove(filename))
{
return true;
}
}
try
{
if (_callbackCanRemoveFolder != null)
{
if (!_callbackCanRemoveFolder(path))
{
return false;
}
}
Directory.Delete(path);
Count++;
result = null;
}
catch (Exception ex)
{
try
{
File.SetAttributes(path, FileAttributes.Normal);
Directory.Delete(path);
Count++;
result = null;
}
catch (Exception)
{
result = "Try to delete directory exception: " + ex.ToString();
}
}
}
else
{
try
{
if (File.Exists(path))
{
if (_callbackCanRemoveFile != null)
{
if (!_callbackCanRemoveFile(path))
{
return false;
}
}
File.Delete(path);
Count++;
result = null;
}
else
{
Debug.Print($"File does not exists {path}");
}
}
catch (Exception ex)
{
try
{
File.SetAttributes(path, FileAttributes.Normal);
File.Delete(path);
Count++;
result = null;
}
catch (Exception)
{
result = "Try to delete file exception: " + ex.ToString();
}
}
}
_pathStatus?.Invoke(path, result, Count);
return false;
}
// ******************************************************************
}
}