如何检查IOException是否足够 - 磁盘空间异常类型?

jot*_*bek 63 .net c# diskspace exception-handling ioexception

如何检查IOException"磁盘空间不足"异常类型?

目前我检查消息是否与"磁盘空间不足"相匹配,但我知道如果操作系统语言不是英语,这将不起作用.

Jus*_*tin 72

你需要检查HResult并测试ERROR_DISK_FULL(0x70)ERROR_HANDLE_DISK_FULL(0x27),它们可以HResults通过OR'ing with 转换为0x80070000.

对于.Net Framework 4.5及更高版本,您可以使用以下Exception.HResult属性:

static bool IsDiskFull(Exception ex)
{
    const int HR_ERROR_HANDLE_DISK_FULL = unchecked((int)0x80070027);
    const int HR_ERROR_DISK_FULL = unchecked((int)0x80070070);

    return ex.HResult == HR_ERROR_HANDLE_DISK_FULL 
        || ex.HResult == HR_ERROR_DISK_FULL;
}
Run Code Online (Sandbox Code Playgroud)

对于旧版本,您可以使用Marshal.GetHRForException以获取HResult,但这具有显着的副作用,不建议使用:

static bool IsDiskFull(Exception ex)
{
    const int ERROR_HANDLE_DISK_FULL = 0x27;
    const int ERROR_DISK_FULL = 0x70;

    int win32ErrorCode = Marshal.GetHRForException(ex) & 0xFFFF;
    return win32ErrorCode == ERROR_HANDLE_DISK_FULL || win32ErrorCode == ERROR_DISK_FULL;
}
Run Code Online (Sandbox Code Playgroud)

从MSDN文档:

请注意,GetHRForException方法设置当前线程的IErrorInfo.这可能会导致ThrowExceptionForHR方法等方法出现意外结果, 如果设置了默认使用当前线程的IErrorInfo.

另请参阅如何确定System.IO.IOException的HResult?

  • 另一方面,具有副作用的"Marshal.GetHRForException"非常难看. (3认同)
  • 从.Net-Framework 4.5开始,Exception.HResult的getter不再受到保护.我认为这可以取代GetHRForException调用并摆脱上面提到的副作用. (3认同)
  • 看起来比汉斯的解决方案更清洁. (2认同)
  • @Justin如果您的目标是4.5或更高版本,这将不再是一个好答案。 (2认同)

Bat*_*ech 21

在.NET 4.5中,HResult属性getter现在是Public,因此您不必再使用Marshal.GetHRForException(及其副作用).

http://msdn.microsoft.com/en-us/library/system.exception.hresult(v=vs.110).aspx声明"从.NET Framework 4.5开始,HResult属性的setter受到保护,而其getter在以前版本的.NET Framework中,getter和setter都受到保护"

所以你可以使用贾斯汀的答案,但替换Marshal.GetHRForException(ex)ex.HResult.


ken*_*n2k 13

嗯,这有点hacky,但我们走了.

首先要做的是HResult从异常中获取.由于它是受保护的成员,我们需要一些反思才能获得价值.这是一个扩展方法,可以解决这个问题:

public static class ExceptionExtensions
{
    public static int HResultPublic(this Exception exception)
    {
        var hResult = exception.GetType().GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).Where(z => z.Name.Equals("HResult")).First();
        return (int)hResult.GetValue(exception, null);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,在您的捕获范围中,您可以获得HResult:

catch (Exception ex)
{
    int hResult = ex.HResultPublic();
}
Run Code Online (Sandbox Code Playgroud)

从这里开始,你必须解释HResult.你需要这个链接.

我们需要得到ErrorCode存储在值的16位的第一位,所以这里有一些位操作:

int errorCode = (int)(hResult & 0x0000FFFF);
Run Code Online (Sandbox Code Playgroud)

现在,请参阅系统错误代码列表,我们在这里:

ERROR_DISK_FULL
112 (0x70)
Run Code Online (Sandbox Code Playgroud)

所以测试它使用:

switch (errorCode)
{
    case 112:
        // Disk full
}
Run Code Online (Sandbox Code Playgroud)

也许有一些"更高级别"的功能来获得所有这些东西,但至少它是有效的.


Dom*_*alo 11

最简单的内联解决方案(min .NET 4.5和C#6):

try
{
    //...
}
catch (IOException ex) when ((ex.HResult & 0xFFFF) == 0x27 || (ex.HResult & 0xFFFF) == 0x70)
{
    //...
}
Run Code Online (Sandbox Code Playgroud)