ZetCode

Java IOException 类

最后修改时间:2025 年 4 月 16 日

java.io.IOException 是一个检查型异常,表示 I/O 操作失败。 它是 Java 中许多与 I/O 相关的异常的基类。 常见的情况包括文件访问问题、网络问题和流错误。

IOException 继承自 Exception,必须被捕获或在方法签名中声明。 它提供了使用消息和原因创建异常的构造函数。 许多 Java I/O 操作抛出此异常或其子类。

IOException 类概述

IOException 表示一般的 I/O 失败情况。 当输入或输出操作失败或中断时,会抛出此异常。 类层次结构包含许多专门的 I/O 异常,用于处理特定的错误情况。

public class IOException extends Exception {
    public IOException();
    public IOException(String message);
    public IOException(String message, Throwable cause);
    public IOException(Throwable cause);
}

上面的代码展示了 IOException 中可用的构造函数。 这些构造函数允许创建带有描述性消息和底层原因的异常。 该类继承了标准的异常方法,例如 getMessagegetCause

基本的 IOException 处理

此示例演示了读取文件时基本的 IOException 处理。 try-catch 块捕获潜在的 I/O 失败。 始终在 finally 中关闭资源或使用 try-with-resources 以进行正确的清理。

Main.java
import java.io.FileReader;
import java.io.IOException;

public class Main {

    public static void main(String[] args) {
        FileReader reader = null;
        try {
            reader = new FileReader("nonexistent.txt");
            int character;
            while ((character = reader.read()) != -1) {
                System.out.print((char) character);
            }
        } catch (IOException e) {
            System.err.println("Error reading file: " + e.getMessage());
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (IOException e) {
                System.err.println("Error closing file: " + e.getMessage());
            }
        }
    }
}

此示例尝试读取一个不存在的文件,从而触发 IOException。 catch 块处理该错误并打印一条消息。 finally 块确保读取器被正确关闭。 请注意,close() 也可能抛出 IOException。

带有 Try-With-Resources 的 IOException

Java 7 引入了 try-with-resources 以进行自动资源管理。 这通过自动处理清理来简化 I/O 代码。 在 try 标头中声明的资源在块退出时关闭。

Main.java
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class Main {

    public static void main(String[] args) {
        try (BufferedReader br = new BufferedReader(
                new FileReader("example.txt"))) {
            
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.err.println("I/O error occurred: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

此示例使用 try-with-resources 来处理文件读取。 BufferedReader 在 try 块之后自动关闭。 如果在读取或关闭期间发生 IOException,则会被捕获并处理。 这种方法减少了样板代码。

使用 IOException 的链式异常

IOException 支持异常链接以保留原始原因。 这在包装较低级别的异常时很有用。 以后可以访问该原因以进行详细的错误分析。

Main.java
import java.io.FileInputStream;
import java.io.IOException;

public class Main {

    public static void processFile(String filename) throws IOException {
        try {
            FileInputStream fis = new FileInputStream(filename);
            // Process file contents
            fis.close();
        } catch (IOException e) {
            throw new IOException("Failed to process file: " + filename, e);
        }
    }

    public static void main(String[] args) {
        try {
            processFile("config.dat");
        } catch (IOException e) {
            System.err.println("Error: " + e.getMessage());
            System.err.println("Root cause: " + e.getCause().getMessage());
        }
    }
}

此示例演示了异常链接。 processFile 方法使用附加的上下文包装原始的 IOException。 main 方法可以访问高级消息和根本原因。 这种模式有助于调试。

处理多个 IOExceptions

某些操作可能会抛出不同的 IOException 子类。 您可以单独捕获这些异常或将它们一起处理。 此示例显示了用于全面错误处理的两种方法。

Main.java
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class Main {

    public static void main(String[] args) {
        try {
            FileReader reader = new FileReader("data.txt");
            // Simulate different error conditions
            if (Math.random() > 0.5) {
                throw new java.net.SocketException("Network failure");
            }
            reader.close();
        } catch (FileNotFoundException e) {
            System.err.println("File not found: " + e.getMessage());
        } catch (java.net.SocketException e) {
            System.err.println("Network error: " + e.getMessage());
        } catch (IOException e) {
            System.err.println("General I/O error: " + e.getMessage());
        }
    }
}

此示例显示了捕获不同的与 I/O 相关的异常。 首先捕获 FileNotFoundException,因为它更具体。 SocketException 处理网络问题。 常规 IOException 捕获所有其他 I/O 问题。 catch 块中的顺序很重要。

创建自定义 IOException

您可以扩展 IOException 以创建自定义异常类型。 这对于特定于应用程序的错误情况很有用。 自定义异常可以包含额外的字段和方法。

Main.java
import java.io.IOException;

class InvalidDataFormatException extends IOException {
    private int lineNumber;
    
    public InvalidDataFormatException(String message, int lineNumber) {
        super(message);
        this.lineNumber = lineNumber;
    }
    
    public int getLineNumber() {
        return lineNumber;
    }
}

public class Main {
    public static void processData() throws InvalidDataFormatException {
        // Simulate finding invalid data at line 42
        throw new InvalidDataFormatException("Invalid CSV format", 42);
    }

    public static void main(String[] args) {
        try {
            processData();
        } catch (InvalidDataFormatException e) {
            System.err.println("Error at line " + e.getLineNumber() + 
                ": " + e.getMessage());
        }
    }
}

此示例创建了一个自定义的 InvalidDataFormatException。 它包含一个行号字段,用于提供额外的上下文。 异常被抛出并捕获,可以访问消息和行号。 自定义异常提高了错误处理的精确度。

IOException 最佳实践

正确的 IOException 处理对于健壮的应用程序至关重要。 始终提供有意义的错误消息并考虑记录异常。 使用 try-with-resources 进行自动清理。 保留异常链以进行调试。

Main.java
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Main {
    private static final Logger logger = Logger.getLogger(Main.class.getName());

    public static void processFile(String path) {
        try (BufferedReader br = new BufferedReader(new FileReader(path))) {
            String line;
            while ((line = br.readLine()) != null) {
                // Process each line
                if (line.isEmpty()) {
                    throw new IOException("Empty line found");
                }
            }
        } catch (IOException e) {
            logger.log(Level.SEVERE, "Failed to process file: " + path, e);
            throw new RuntimeException("File processing failed", e);
        }
    }

    public static void main(String[] args) {
        try {
            processFile("input.dat");
        } catch (RuntimeException e) {
            System.err.println("Application error: " + e.getMessage());
        }
    }
}

此示例演示了几个最佳实践。 它使用 try-with-resources,记录带有上下文的异常,并将 IOException 包装在 RuntimeException 中。 原始异常保留在原因链中。 这种方法提供了良好的错误信息,同时保持应用程序流程。

来源

Java IOException 类文档

在本文中,我们介绍了 Java IOException 类的基本方面。 理解这些概念对于 Java 应用程序中健壮的 I/O 处理至关重要。

作者

我叫 Jan Bodnar,是一位经验丰富的程序员。 我于 2007 年开始撰写编程文章,此后撰写了 1,400 多篇文章和 8 本电子书。 凭借超过八年的教学经验,我致力于分享我的知识并帮助他人掌握编程概念。

列出所有Java教程