ZetCode

C# IOException

最后修改于 2025 年 4 月 20 日

本教程介绍了如何在 C# 中使用 IOException 类来处理文件 I/O 错误。IOException 代表在输入/输出操作期间发生的错误。

IOException 类在文件操作期间发生 I/O 错误时抛出。 它是更具体的 I/O 异常的基类。

IOException 处理各种文件系统错误,如缺少文件、访问冲突和设备错误。 它通过其属性提供详细的错误信息。

基本的 IOException 处理

此示例演示了在尝试读取不存在的文件时捕获 IOException。 它展示了基本的异常处理结构。

Program.cs
using System;
using System.IO;

class Program
{
    static void Main()
    {
        try
        {
            string content = File.ReadAllText("nonexistent.txt");
            Console.WriteLine(content);
        }
        catch (IOException ex)
        {
            Console.WriteLine($"IO Error: {ex.Message}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"General Error: {ex.Message}");
        }
    }
}

该代码尝试读取一个不存在的文件。 IOException catch 块处理特定的错误。 该示例展示了一种典型的模式,其中更具体的异常在一般异常之前被捕获。

当文件不存在时,File.ReadAllText 会抛出一个 IOException。 catch 块捕获此异常并显示其 Message 属性。 这为用户提供了关于文件操作出错原因的有意义的错误信息。

处理文件访问冲突

此示例展示了当由于权限或文件锁导致文件访问被拒绝时如何处理 IOException。

Program.cs
using System;
using System.IO;

class Program
{
    static void Main()
    {
        try
        {
            // Try to open a file that's already in use
            using (var fs = new FileStream("lockedfile.txt", 
                   FileMode.Open, FileAccess.ReadWrite))
            {
                Console.WriteLine("File opened successfully");
            }
        }
        catch (IOException ex)
        {
            Console.WriteLine($"Access Error: {ex.Message}");
            
            if (ex.HResult == -2147024864) // ERROR_SHARING_VIOLATION
            {
                Console.WriteLine("The file is being used by another process");
            }
        }
    }
}

该代码尝试打开一个可能被另一个进程锁定的文件。 IOException 捕获访问冲突。 该示例检查 HResult 属性以识别特定的错误情况。

当文件被另一个应用程序锁定时,Windows 会阻止访问。 IOException 提供了有关此情况的详细信息。 通过检查 HResult 值,我们可以确定访问问题的确切性质。 这允许更具体的错误处理和用户反馈。

在操作之前检查文件是否存在

此示例演示了将 File.Exists 检查与 IOException 处理相结合以实现健壮的文件操作。

Program.cs
using System;
using System.IO;

class Program
{
    static void Main()
    {
        string filePath = "data.txt";
        
        if (!File.Exists(filePath))
        {
            Console.WriteLine("File does not exist");
            return;
        }

        try
        {
            string content = File.ReadAllText(filePath);
            Console.WriteLine(content);
        }
        catch (IOException ex)
        {
            Console.WriteLine($"Error reading file: {ex.Message}");
        }
    }
}

该代码首先检查文件是否存在,然后再尝试读取它。 这可以防止一些 IOException 情况。 但是,它仍然包括异常处理,因为可能会发生竞争条件。

在检查 File.Exists 和实际读取文件之间,该文件可能会被删除或变得无法访问。 因此,即使进行存在性检查,IOException 处理仍然是必要的。 这种模式既提供了主动检查又提供了被动错误处理。

处理目录操作

此示例展示了在使用目录时(包括目录无法访问的情况)如何处理 IOException。

Program.cs
using System;
using System.IO;

class Program
{
    static void Main()
    {
        string dirPath = @"C:\RestrictedFolder";
        
        try
        {
            string[] files = Directory.GetFiles(dirPath);
            foreach (var file in files)
            {
                Console.WriteLine(file);
            }
        }
        catch (IOException ex)
        {
            Console.WriteLine($"Directory Error: {ex.Message}");
        }
        catch (UnauthorizedAccessException ex)
        {
            Console.WriteLine($"Permission Denied: {ex.Message}");
        }
    }
}

该代码尝试列出可能受限制的目录中的文件。 IOException 处理一般的 I/O 错误,而 UnauthorizedAccessException 捕获权限问题。 这展示了如何处理多个相关的异常。

目录操作可能会因为多种原因而失败 - 目录可能不存在,路径可能无效,或者权限可能不足。 该示例演示了如何使用适当的异常类型处理这些不同的场景,同时保持清晰的错误报告。

处理驱动器错误

此示例演示了在处理与驱动器相关的错误(例如不可用的网络驱动器)时如何处理 IOException。

Program.cs
using System;
using System.IO;

class Program
{
    static void Main()
    {
        string filePath = @"Z:\networkfile.txt";
        
        try
        {
            string content = File.ReadAllText(filePath);
            Console.WriteLine(content);
        }
        catch (IOException ex) when (ex.Message.Contains("not available"))
        {
            Console.WriteLine("Network drive not available");
        }
        catch (IOException ex)
        {
            Console.WriteLine($"Drive Error: {ex.Message}");
        }
    }
}

该代码尝试从可能断开连接的网络驱动器读取。 第一个 catch 使用 when 子句来过滤特定的错误消息。 这展示了高级的异常过滤技术。

网络驱动器可能会因为多种原因而变得不可用。 该示例展示了如何在仍然处理其他 I/O 错误的同时检测到此特定情况。 when 子句允许基于错误消息内容进行更精确的异常处理。

处理文件复制操作

此示例演示了在文件复制操作期间如何处理 IOException,包括磁盘已满的情况。

Program.cs
using System;
using System.IO;

class Program
{
    static void Main()
    {
        string source = "largefile.dat";
        string destination = "copy.dat";
        
        try
        {
            File.Copy(source, destination, overwrite: true);
            Console.WriteLine("File copied successfully");
        }
        catch (IOException ex) when (ex.Message.Contains("enough space"))
        {
            Console.WriteLine("Insufficient disk space");
        }
        catch (IOException ex)
        {
            Console.WriteLine($"Copy Error: {ex.Message}");
        }
    }
}

该代码尝试复制一个可能超出可用磁盘空间的大文件。 第一个 catch 块专门处理磁盘空间错误。 其他 I/O 错误由更通用的 IOException 处理程序捕获。

文件复制操作可能会因为多种原因而失败 - 找不到源文件、目标文件被锁定或磁盘空间不足。 该示例展示了如何在保持清晰的错误处理的同时区分这些情况。 when 子句有助于识别通用 IOException 类中的特定错误情况。

自定义 IOException 处理

此示例展示了如何为特定的 IOException 场景创建自定义异常处理逻辑。

Program.cs
using System;
using System.IO;
using System.Runtime.InteropServices;

class Program
{
    [DllImport("kernel32.dll")]
    private static extern int GetLastError();

    static void Main()
    {
        string filePath = "important.config";
        
        try
        {
            using (var fs = new FileStream(filePath, 
                   FileMode.Open, FileAccess.ReadWrite))
            {
                // Work with the file
            }
        }
        catch (IOException ex)
        {
            int errorCode = GetLastError();
            
            switch (errorCode)
            {
                case 32: // ERROR_SHARING_VIOLATION
                    Console.WriteLine("File is locked by another process");
                    break;
                case 183: // ERROR_ALREADY_EXISTS
                    Console.WriteLine("File already exists");
                    break;
                default:
                    Console.WriteLine($"IO Error {errorCode}: {ex.Message}");
                    break;
            }
        }
    }
}

该代码使用 Windows API 获取 IOException 的详细错误代码。 这允许基于系统错误代码进行非常具体的错误处理。 该示例演示了与本机 Windows API 的高级集成。

通过在 IOException 发生后调用 GetLastError,我们可以访问底层的系统错误代码。 这提供了比标准异常消息更详细的信息。 该示例展示了如何将这些错误代码映射到特定的错误情况,并为每种情况提供适当的处理。

来源

IOException 类文档

本教程介绍了如何使用 C# 中的 IOException 处理 I/O 错误,包括文件操作、目录访问和自定义错误处理。

作者

我叫 Jan Bodnar,是一位热情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直在撰写编程文章。 迄今为止,我已经撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 C# 教程