5

让我们看一下这个代码示例:

using System;
using System.IO;

namespace ConsoleApplication25
{
    class Program
    {
        static void Main()
        {
            var bytes = new byte[] { 1, 2, 3 };
            var trimChars = new[] { '"' };
            var path = Environment.CommandLine.Trim().Trim(trimChars);
            File.WriteAllBytes(path, bytes);
        }
    }
}

运行这个(程序试图覆盖自己)会导致抛出异常:

System.IO.IOException was unhandled
Message=The process cannot access the file 'F:\TEMP\ConsoleApplication25\ConsoleApplication25\bin\Debug\ConsoleApplication25.vshost.exe' because it is being used by another process.
Source=mscorlib
StackTrace:
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
   at System.IO.File.WriteAllBytes(String path, Byte[] bytes)
   at ConsoleApplication25.Program.Main() in F:\TEMP\ConsoleApplication25\ConsoleApplication25\Program.cs:line 13
   at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

..这是意料之中且显而易见的。但是, IOException 的实例并没有为我提供任何可靠的信息,我可以使用这些信息以编程方式检测文件是否正在被另一个进程使用。只是Message物业告诉你,但这取决于当地文化,所以我不能依赖它。

知道如何处理吗?如果文件正在被另一个进程使用,我需要采取特殊措施,但我找不到将这种情况与其他(异常)情况分开的方法。

4

2 回答 2

13

这个问题可能是这个问题的重复所以这里的答案非常接近接受的问题。但是,要检查的错误代码存在一些显着差异。最终,您可能会考虑支持另一个问题的答案。

您可以按照答案进行操作,但请检查ERROR_SHARING_VIOLATION(0x20)

const long ERROR_SHARING_VIOLATION = 0x20;
const long ERROR_LOCK_VIOLATION = 0x21;

//Only for .NET <4.5: long win32ErrorCode = Marshal.GetHRForException(ex) & 0xFFFF;
long win32ErrorCode = ex.HResult & 0xFFFF; // .NET 4.5+
if (win32ErrorCode == ERROR_SHARING_VIOLATION || win32ErrorCode == ERROR_LOCK_VIOLATION )
{
    // file in use.
}

但是,请注意,使用GetHRForException具有您可能不希望有的副作用。

更新正如评论者@jmn2 指出的那样,从.NET 4.5 开始,该Exception.HResult属性现在是公开的。所以没有必要使用GetHRForException- 当然,除非你需要支持 4.5 之前的代码。

要编写一个运行时向后兼容的“包装器”,您应该HResult通过反射调用,因为(如果您使用GetPropertiesand BindingFlags.Public BindingFlags.NonPublic它将适用于所有版本的 .NET 框架(参见这个非常相关的答案)。

于 2012-08-21T12:45:38.267 回答
1

这是类似的问题

您将需要检查异常的 HResult。然后检查它的值:

int hr = Marshal.GetHRForException( ex );

这是共享锁违规的代码

于 2012-08-21T12:38:54.910 回答