简体   繁体   English

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

[英]Can't delete files from a shared folder with File.Delete()

"System.UnauthorizedAccessException" - I've seen this message on my screen for 2 days and just couldn't figured out why. “System.UnauthorizedAccessException” - 我已经在屏幕上看到这条消息 2 天了,只是不知道为什么。 I've checked all the possible reasons in my knowledge to make it work but fail.我已经检查了我所知道的所有可能的原因,使其工作但失败了。 Here is the summary of what I have checked:这是我检查过的内容的摘要:

  1. The file in the shared drive (mapped drive in the local network) is not ready only and the full access permissions are granted to everyone.共享驱动器(本地网络中的映射驱动器)中的文件尚未准备好,并且授予每个人完全访问权限。 The folders in the file path are also been set to grant full access permissions to everyone.文件路径中的文件夹也被设置为授予所有人完全访问权限。
  2. I can delete the file manually我可以手动删除文件
  3. the file was created by the same user (me) and I need to delete it when there is a revision.该文件是由同一用户(我)创建的,当有修订时我需要将其删除。 (delete the old one and put the new one in) (删除旧的并放入新的)
  4. when I change the destination folder to local drive (c:..), everything works well.当我将目标文件夹更改为本地驱动器(c:..)时,一切正常。 No problems to delete files.删除文件没有问题。 But it won't work (System.UnauthorizedAccessException) when I change it to the shared drive (H: drive).但是当我将其更改为共享驱动器(H:驱动器)时,它不起作用(System.UnauthorizedAccessException)。
  5. Here are the codes related to the exception:以下是与异常相关的代码:

fdname = inipath + Convert.ToString(ynum); 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();

在此处输入图像描述在此处输入图像描述

It is a permission issue but I just couldn't figure out where the problem is.这是一个权限问题,但我就是不知道问题出在哪里。 Here is the debugging details:以下是调试详细信息:

System.UnauthorizedAccessException System.UnauthorizedAccessException

HResult=0x80070005 H结果=0x80070005

Message=Access to the path 'H:\OrderFiles\21\21003\2100337\PS2100337.pdf' is denied.消息=拒绝访问路径“H:\OrderFiles\21\21003\2100337\PS2100337.pdf”。

Source=mscorlib源=mscorlib

StackTrace:堆栈跟踪:

at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)在 System.IO.__Error.WinIOError(Int32 错误代码,字符串可能全路径)

at System.IO.File.InternalDelete(String path, Boolean checkHost)在 System.IO.File.InternalDelete(字符串路径,Boolean checkHost)

at System.IO.File.Delete(String path)在 System.IO.File.Delete(字符串路径)

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

This exception was originally thrown at this call stack: [External Code] OpenOrder.PSForm.crystalReportViewer1_Load(object, System.EventArgs) in PSForm.cs此异常最初是在此调用堆栈中引发的:PSForm.cs 中的 [外部代码] OpenOrder.PSForm.crystalReportViewer1_Load(object, System.EventArgs)

Probably off-topic, but in case it helps.可能是题外话,但以防万一。 I remember having that headache a while ago while trying to replace files on a mapped drive in a machine that had to interact with that and other network locations, often with different credentials.我记得前段时间在尝试替换必须与该位置和其他网络位置交互的机器上的映射驱动器上的文件时遇到了这种头痛,通常使用不同的凭据。 I ended up using a custom impersonation context and passing the domain and credentials each time.我最终使用自定义模拟上下文并每次都传递域和凭据。 I have this method in my FileUtil lib:我的 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();
}

In your case, you'd use it like this:在你的情况下,你会像这样使用它:

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

And the impersonation context ( credit to it's creator ) looks like this:模拟上下文(归功于它的创建者)看起来像这样:

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

Please try to check for less convoluted solutions before jumping into this one.在进入这个之前,请尝试检查不太复杂的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM