无法使用 File.Delete() 从共享文件夹中删除文件

时间:2021-06-05 01:09:24

标签: c#

“System.UnauthorizedAccessException” - 我已经在屏幕上看到这条消息 2 天了,只是想不通为什么。 我已经检查了我所知的所有可能的原因,使其工作但失败。以下是我检查过的摘要:

  1. 共享驱动器(本地网络中的映射驱动器)中的文件没有准备好,完全访问权限授予每个人。文件路径中的文件夹也设置为向所有人授予完全访问权限。
  2. 我可以手动删除文件
  3. 该文件是由同一个用户(我)创建的,当有修订时我需要删除它。 (删除旧的并放入新的)
  4. 当我将目标文件夹更改为本地驱动器 (c:...) 时,一切正常。删除文件没有问题。但是当我将其更改为共享驱动器(H:驱动器)时,它将不起作用(System.UnauthorizedAccessException)。
  5. 以下是与异常相关的代码:

fdname = inipath + Convert.ToString(ynum);

        if (! Directory.Exists(fdname))
            System.IO.Directory.CreateDirectory(fdname);
        fdname = inipath + Convert.ToString(ynum) + "\\" + Convert.ToString(fpathnum);
        if (!Directory.Exists(fdname))
            System.IO.Directory.CreateDirectory(fdname);
        fdname = inipath + Convert.ToString(ynum) + "\\" + Convert.ToString(fpathnum) + "\\" + Convert.ToString(salodrnum);
        if (!Directory.Exists(fdname))
        {
            System.IO.Directory.CreateDirectory(fdname);
            File.SetAttributes(fdname, FileAttributes.Normal);
            // File.SetAttributes(fdname, File.GetAttributes(fdname) & ~FileAttributes.ReadOnly);  //remove read ony
        }
        if (File.Exists(fdname + @"\PS" + salodrnum + ".pdf"))
        {
            File.SetAttributes(fdname + @"\PS" + salodrnum + ".pdf", FileAttributes.Normal);
            File.Delete(fdname + @"\PS" + salodrnum + ".pdf");
        }

        doc.ExportToDisk(CrystalDecisions.Shared.ExportFormatType.PortableDocFormat, fdname + @"\PS" + salodrnum + ".pdf");
        File.SetAttributes(fdname + @"\PS" + salodrnum + ".pdf", FileAttributes.Normal);
        procForm.Close();

enter image description here enter image description here

这是一个权限问题,但我无法弄清楚问题出在哪里。这是调试细节:

<块引用>

System.UnauthorizedAccessException

<块引用>

HResult=0x80070005

<块引用>

Message=拒绝访问路径“H:\OrderFiles\21\21003\2100337\PS2100337.pdf”。

<块引用>

源=mscorlib

<块引用>

堆栈跟踪:

<块引用>

在 System.IO.__Error.WinIOError(Int32 errorCode, String MaybeFullPath)

<块引用>

在 System.IO.File.InternalDelete(String path, Boolean checkHost)

<块引用>

在 System.IO.File.Delete(String path)

<块引用>

在 OpenOrder.PSForm.crystalReportViewer1_Load(Object sender, EventArgs e) 在 C:\SG100sys\Source Codes\OpenOrder\OpenOrder\PSForm.cs:line 188

<块引用>

这个异常最初是在这个调用栈上抛出的: 【外码】 PSForm.cs 中的 OpenOrder.PSForm.crystalReportViewer1_Load(object, System.EventArgs)

1 个答案:

答案 0 :(得分:2)

可能是题外话,但以防万一。 我记得不久前在尝试替换必须与该机器和其他网络位置交互的机器中映射驱动器上的文件时遇到了这种头痛,通常使用不同的凭据。我最终使用自定义 impersonation 上下文并每次都传递域和凭据。我的 FileUtil 库中有这个方法:

public static void InteractWithNetworkFolder(Action MethodThatInteractsWithTheFolder, string Domain, string Username, string Password)
{
    var ImpersonationContext = new WrappedImpersonationContext(Domain, Username, Password);
    ImpersonationContext.Enter();
    MethodThatInteractsWithTheFolder.Invoke();
    ImpersonationContext.Leave();
}

在你的情况下,你会像这样使用它:

FileUtil.InteractWithNetworkFolder(() => File.Delete(PathToYourFile), Domain, Username, Password)

模拟上下文 (credit to it's creator) 如下所示:

public sealed class WrappedImpersonationContext
{
    public enum LogonType : int
    {
        Interactive = 2,
        Network = 3,
        Batch = 4,
        Service = 5,
        Unlock = 7,
        NetworkClearText = 8,
        NewCredentials = 9
    }

    public enum LogonProvider : int
    {
        Default = 0,  // LOGON32_PROVIDER_DEFAULT
        WinNT35 = 1,
        WinNT40 = 2,  // Use the NTLM logon provider.
        WinNT50 = 3   // Use the negotiate logon provider.
    }

    [DllImport("advapi32.dll", EntryPoint = "LogonUserW", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern bool LogonUser(String lpszUsername, String lpszDomain,
        String lpszPassword, LogonType dwLogonType, LogonProvider dwLogonProvider, ref IntPtr phToken);

    [DllImport("kernel32.dll")]
    public extern static bool CloseHandle(IntPtr handle);

    private string _domain, _password, _username;
    private IntPtr _token;
    private WindowsImpersonationContext _context;

    private bool IsInContext
    {
        get { return _context != null; }
    }

    public WrappedImpersonationContext(string domain, string username, string password)
    {
        _domain = String.IsNullOrEmpty(domain) ? "." : domain;
        _username = username;
        _password = password;
    }

    // Changes the Windows identity of this thread. Make sure to always call Leave() at the end.
    [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
    public void Enter()
    {
        if (IsInContext)
            return;

        _token = IntPtr.Zero;
        bool logonSuccessfull = LogonUser(_username, _domain, _password, LogonType.NewCredentials, LogonProvider.WinNT50, ref _token);
        if (!logonSuccessfull)
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }
        WindowsIdentity identity = new WindowsIdentity(_token);
        _context = identity.Impersonate();

        Debug.WriteLine(WindowsIdentity.GetCurrent().Name);
    }

    [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
    public void Leave()
    {
        if (!IsInContext)
            return;

        _context.Undo();

        if (_token != IntPtr.Zero)
        {
            CloseHandle(_token);
        }
        _context = null;
    }
}

在跳到这个之前,请尝试检查不太复杂的解决方案。

相关问题