0

我编写了代码以递归方式删除具有所有结构的文件夹。

我得到System.IO.DirectoryNotFoundExceptionFile.Delete一个有效的文件名,我从Directory.GetFiles(path). 我之前添加File.Exists过,它告诉我该文件不存在,我可以在资源管理器中看到它。

我知道我可以做到,SHFileOperation应该可以正常工作。但我想使用本机 C#(没有直接的 Windows API)。

我红色:.NET 4.6.2 和 Windows 10 上的长路径,并在本地组策略编辑器中设置启用“启用 Win 32 长路径”。

我正在使用 .NET Framework 4.7.2。

有谁可以告诉我我的代码有什么问题?或者我能做些什么来让它发挥作用?

错误的路径是:

'E:\CobianBackupOld\cn1629\AppData\Local\Packages\Microsoft.Windows.Cortana_cw5n1h2txyewy\LocalState\AppIconCache\100\{7C5A40EF-A0FB-4BFC-874A-C0F2E0B9FA8E}_Microsoft Visual Studio 9_0_Application_PreEmptive Solutions_Dotfuscator Community Edition_dotfuscator_exe'

我是该文件的所有者(我有权删除它)。

更新

我部分修复了我的错误,但想知道如何正确修复它(最近的框架应该支持长路径???)。我的实际解决方法是在我的递归函数开始时添加该代码

if (path.Length < 2 || !path.StartsWith(@"\\"))
{
  path = @"\\?\" + path;
}

UPDATE 2 虽然没有直接关系...只是想提一个重点,C# File.Delete 或 Directory.Delete 不会删除只读文件或文件夹,您还应该在删除它们之前将它们的权限更改为正常,否则您将获得访问权限拒绝错误。

仅供参考,我的代码是:

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;
        }

        // ******************************************************************

    }

}
4

1 回答 1

0

虽然没有我希望的那么完美,但我通过使用前缀“\?\”并确保在删除之前将属性设置为正常来修复了我的错误。

我仍然不undertsand为什么我还要这样做???为什么它在最近的 .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;
        }

        // ******************************************************************

    }

}
于 2019-08-28T17:57:30.477 回答