C# IOException:进程无法访问文件';文件路径';因为它正被另一个进程使用

C# IOException:进程无法访问文件';文件路径';因为它正被另一个进程使用,c#,.net,language-agnostic,ioexception,C#,.net,Language Agnostic,Ioexception,我有一些代码,当它执行时,它抛出一个IOException,说 进程无法访问文件“filename”,因为它正被使用 另一个过程 这意味着什么?我能做些什么?原因是什么? 错误信息非常清楚:您试图访问一个文件,但由于另一个进程(甚至是同一个进程)正在对其执行某些操作(并且它不允许任何共享),因此无法访问该文件 调试 这可能很容易解决(或者很难理解),这取决于您的具体场景。让我们看看 您的进程是唯一访问该文件的进程 你确定另一个过程是你自己的过程。如果您知道您在程序的另一部分中打开了该文件,那么首

我有一些代码,当它执行时,它抛出一个
IOException
,说

进程无法访问文件“filename”,因为它正被使用 另一个过程

这意味着什么?我能做些什么?

原因是什么? 错误信息非常清楚:您试图访问一个文件,但由于另一个进程(甚至是同一个进程)正在对其执行某些操作(并且它不允许任何共享),因此无法访问该文件

调试 这可能很容易解决(或者很难理解),这取决于您的具体场景。让我们看看

您的进程是唯一访问该文件的进程
你确定另一个过程是你自己的过程。如果您知道您在程序的另一部分中打开了该文件,那么首先您必须检查每次使用后是否正确关闭了文件句柄。下面是一个带有此错误的代码示例:

var stream = new FileStream(path, FileAccess.Read);
var reader = new StreamReader(stream);
// Read data from this file, when I'm done I don't need it any more
File.Delete(path); // IOException: file is in use
幸运的是,
FileStream
实现了
IDisposable
,因此使用语句可以轻松地将所有代码包装到
中:

using (var stream = File.Open("myfile.txt", FileMode.Open)) {
    // Use stream
}

// Here stream is not accessible and it has been closed (also if
// an exception is thrown and stack unrolled
此模式还将确保文件在出现异常时不会保持打开状态(这可能是文件正在使用的原因:出现了问题,没有人关闭它;请参阅示例)

如果一切正常(您确信总是关闭打开的每个文件,即使在出现异常的情况下),并且有多个工作线程,那么您有两个选择:重新编写代码以序列化文件访问(不总是可行的,也不总是需要的)或应用重试模式。这是一种非常常见的I/O操作模式:您尝试执行某些操作,如果出现错误,请等待并重试(例如,您是否问过自己,为什么Windows Shell会花一些时间通知您某个文件正在使用且无法删除?)。在C语言中,它很容易实现(另请参见关于和的更好示例)

在这种情况下,
ReadAllText()
将失败,因为文件正在使用中(
file.Open()
在前面的行中)。事先打开文件不仅没有必要,而且是错误的。这同样适用于所有不返回您正在使用的文件句柄的
文件
函数:
文件.ReadAllText()
文件.WriteAllText()
文件.ReadAllLines()
文件.writeAllines()
和其他函数(如
文件.AppendAllXyz()
函数)将自己打开和关闭文件

您的进程不是唯一访问该文件的进程
如果您的进程不是唯一一个访问该文件的进程,那么交互将更加困难。重试模式会有所帮助(如果文件不应该被其他人打开,但它确实被打开了,那么您需要一个类似Process Explorer的实用程序来检查谁在做什么)

如何避免 如果适用,请始终使用using语句打开文件。如前一段所述,它将积极帮助您避免许多常见错误(有关如何不使用它的示例,请参见)

如果可能,尝试确定谁拥有对特定文件的访问权,并通过一些众所周知的方法集中访问。例如,如果您有一个数据文件,您的程序在其中读取和写入数据,那么您应该将所有I/O代码封装在一个类中。它将使调试更容易(因为您可以始终在那里放置一个断点,并查看谁在做什么),而且它还将成为多访问的同步点(如果需要)

别忘了I/O操作总是会失败,一个常见的例子是:

if (File.Exists(path))
    File.Delete(path);
如果有人在
file.Exists()
之后但在
file.Delete()
之前删除文件,那么它会在您可能错误地感到安全的地方抛出
IOException

每当可能的时候,应用重试模式,如果你使用 FielSistMeWestHeule/Cuff>,考虑推迟动作(因为你会得到通知,但是应用程序可能仍然完全与该文件一起工作)。 高级场景
这并不总是那么容易,所以您可能需要与其他人共享访问权限。例如,如果你从头读到尾,你至少有两个选择

1) 使用正确的同步功能共享相同的
FileStream
(因为它不是线程安全的)。有关示例,请参见和帖子

2) 使用
FileShare
枚举指示操作系统允许其他进程(或您自己进程的其他部分)同时访问同一文件

using (var stream = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.Read))
{
}
在这个例子中,我展示了如何打开一个文件进行写入和共享以进行读取;请注意,当读写重叠时,会导致数据未定义或无效。这是阅读时必须处理的情况。还请注意,这不会使对
流的访问成为线程安全的,因此除非以某种方式同步访问,否则无法与多个线程共享此对象(请参见前面的链接)。还有其他的共享选项可用,它们打开了更复杂的场景。有关更多详细信息,请参阅

一般来说,N个进程可以一起读取同一个文件,但只有一个进程应该写入。在受控场景中,您甚至可以启用并发写入,但这不能概括为本答案中的几个文本段落


是否可以解锁另一进程使用的文件?它并不总是安全的,也不那么容易,但确实如此。

我遇到了以下导致相同错误的情况:

  • 将文件上载到服务器
  • 然后在上传旧文件后将其清除
大多数文件都很小,但也有一些文件很大,因此尝试删除这些文件会导致“无法访问文件”错误

然而,这并不容易找到,解决方案就像“让任务完成执行”一样简单:


上载时出现问题
if (File.Exists(path))
    File.Delete(path);
using (var stream = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.Read))
{
}
using (var wc = new WebClient())
{
   var tskResult = wc.UploadFileTaskAsync(_address, _fileName);
   tskResult.Wait(); 
}
//C# .NET
var image = Image.FromFile(filePath);

image.Dispose(); // this removes all resources

//later...

File.Delete(filePath); //now works
using (var stream = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.ReadWrite))
{
}
public static SendEmail()
{
           MailMessage mMailMessage = new MailMessage();
           //setup other email stuff

            if (File.Exists(attachmentPath))
            {
                Attachment attachment = new Attachment(attachmentPath);
                mMailMessage.Attachments.Add(attachment);
                attachment.Dispose(); //disposing the Attachment object
            }
} 
using (FileStream stream = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.ReadWrite))
{
}
List<Process> lstProcs = ProcessHandler.WhoIsLocking(file);
ProcessHandler.localProcessKill("winword.exe");
ProcessHandler.remoteProcessKill(computerName, txtUserName, txtPassword, "winword.exe");
List<Process> lstProcs = new List<Process>();
lstProcs = ProcessHandler.WhoIsLocking(file);

foreach (Process p in lstProcs)
{
    if (p.MachineName == ".")
        ProcessHandler.localProcessKill(p.ProcessName);
    else
        ProcessHandler.remoteProcessKill(p.MachineName, txtUserName, txtPassword, p.ProcessName);
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Management;

namespace MyProject
{
    public static class ProcessHandler
    {
        [StructLayout(LayoutKind.Sequential)]
        struct RM_UNIQUE_PROCESS
        {
            public int dwProcessId;
            public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
        }

        const int RmRebootReasonNone = 0;
        const int CCH_RM_MAX_APP_NAME = 255;
        const int CCH_RM_MAX_SVC_NAME = 63;

        enum RM_APP_TYPE
        {
            RmUnknownApp = 0,
            RmMainWindow = 1,
            RmOtherWindow = 2,
            RmService = 3,
            RmExplorer = 4,
            RmConsole = 5,
            RmCritical = 1000
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        struct RM_PROCESS_INFO
        {
            public RM_UNIQUE_PROCESS Process;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)]
            public string strAppName;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)]
            public string strServiceShortName;

            public RM_APP_TYPE ApplicationType;
            public uint AppStatus;
            public uint TSSessionId;
            [MarshalAs(UnmanagedType.Bool)]
            public bool bRestartable;
        }

        [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
        static extern int RmRegisterResources(uint pSessionHandle,
                                            UInt32 nFiles,
                                            string[] rgsFilenames,
                                            UInt32 nApplications,
                                            [In] RM_UNIQUE_PROCESS[] rgApplications,
                                            UInt32 nServices,
                                            string[] rgsServiceNames);

        [DllImport("rstrtmgr.dll", CharSet = CharSet.Auto)]
        static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey);

        [DllImport("rstrtmgr.dll")]
        static extern int RmEndSession(uint pSessionHandle);

        [DllImport("rstrtmgr.dll")]
        static extern int RmGetList(uint dwSessionHandle,
                                    out uint pnProcInfoNeeded,
                                    ref uint pnProcInfo,
                                    [In, Out] RM_PROCESS_INFO[] rgAffectedApps,
                                    ref uint lpdwRebootReasons);

        /// <summary>
        /// Find out what process(es) have a lock on the specified file.
        /// </summary>
        /// <param name="path">Path of the file.</param>
        /// <returns>Processes locking the file</returns>
        /// <remarks>See also:
        /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373661(v=vs.85).aspx
        /// http://wyupdate.googlecode.com/svn-history/r401/trunk/frmFilesInUse.cs (no copyright in code at time of viewing)
        /// 
        /// </remarks>
        static public List<Process> WhoIsLocking(string path)
        {
            uint handle;
            string key = Guid.NewGuid().ToString();
            List<Process> processes = new List<Process>();

            int res = RmStartSession(out handle, 0, key);
            if (res != 0) throw new Exception("Could not begin restart session.  Unable to determine file locker.");

            try
            {
                const int ERROR_MORE_DATA = 234;
                uint pnProcInfoNeeded = 0,
                    pnProcInfo = 0,
                    lpdwRebootReasons = RmRebootReasonNone;

                string[] resources = new string[] { path }; // Just checking on one resource.

                res = RmRegisterResources(handle, (uint)resources.Length, resources, 0, null, 0, null);

                if (res != 0) throw new Exception("Could not register resource.");

                //Note: there's a race condition here -- the first call to RmGetList() returns
                //      the total number of process. However, when we call RmGetList() again to get
                //      the actual processes this number may have increased.
                res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, null, ref lpdwRebootReasons);

                if (res == ERROR_MORE_DATA)
                {
                    // Create an array to store the process results
                    RM_PROCESS_INFO[] processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded];
                    pnProcInfo = pnProcInfoNeeded;

                    // Get the list
                    res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons);
                    if (res == 0)
                    {
                        processes = new List<Process>((int)pnProcInfo);

                        // Enumerate all of the results and add them to the 
                        // list to be returned
                        for (int i = 0; i < pnProcInfo; i++)
                        {
                            try
                            {
                                processes.Add(Process.GetProcessById(processInfo[i].Process.dwProcessId));
                            }
                            // catch the error -- in case the process is no longer running
                            catch (ArgumentException) { }
                        }
                    }
                    else throw new Exception("Could not list processes locking resource.");
                }
                else if (res != 0) throw new Exception("Could not list processes locking resource. Failed to get size of result.");
            }
            finally
            {
                RmEndSession(handle);
            }

            return processes;
        }

        public static void remoteProcessKill(string computerName, string userName, string pword, string processName)
        {
            var connectoptions = new ConnectionOptions();
            connectoptions.Username = userName;
            connectoptions.Password = pword;

            ManagementScope scope = new ManagementScope(@"\\" + computerName + @"\root\cimv2", connectoptions);

            // WMI query
            var query = new SelectQuery("select * from Win32_process where name = '" + processName + "'");

            using (var searcher = new ManagementObjectSearcher(scope, query))
            {
                foreach (ManagementObject process in searcher.Get()) 
                {
                    process.InvokeMethod("Terminate", null);
                    process.Dispose();
                }
            }            
        }

        public static void localProcessKill(string processName)
        {
            foreach (Process p in Process.GetProcessesByName(processName))
            {
                p.Kill();
            }
        }

        [DllImport("kernel32.dll")]
        public static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, int dwFlags);

        public const int MOVEFILE_DELAY_UNTIL_REBOOT = 0x4;

    }
}
try{
Start:
///Put your file access code here


}catch (Exception ex)
 {
//by anyway you need to handle this error with below code
   if (ex.Message.StartsWith("The process cannot access the file"))
    {
         //Wait for 5 seconds to free that file and then start execution again
         Thread.Sleep(5000);
         goto Start;
    }
 }
using FileStream fs = System.IO.File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
var _path=MyFile.FileName;
using (var stream = new FileStream
    (_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
  { 
    // Your Code! ;
  }