Java 输入输出(IO)

程序离不开 IO——读文件、写文件、网络传输、用户输入。Java 提供了三套 IO 体系:传统字节流/字符流(java.io)、NIO(java.nio)、NIO.2(Files API)。本章带你掌握日常最常用的部分,过滤掉冷门细节。

1. 三套 IO API 的关系

Java IO 经历了三代演进:

新手建议:文件读写直接用 NIO.2(Files.readString),传统字节/字符流了解原理即可。

2. File 类:文件/目录操作

File 类表示文件或目录的路径(不读写内容),可以查询属性、创建、删除、列举:

import java.io.File;
import java.io.IOException;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        // File 类:操作文件/目录的路径(不读写内容)
        File f = new File("test.txt");

        System.out.println(f.exists());       // 是否存在
        System.out.println(f.isFile());       // 是文件吗
        System.out.println(f.isDirectory());  // 是目录吗
        System.out.println(f.length());       // 字节数
        System.out.println(f.getAbsolutePath()); // 绝对路径

        // 创建文件
        if (!f.exists()) {
            boolean ok = f.createNewFile();   // 创建空文件
            System.out.println("创建: " + ok);
        }

        // 创建目录
        File dir = new File("mydir/sub");
        dir.mkdirs();                          // 创建多级目录

        // 列出目录内容
        File[] files = dir.listFiles();
        if (files != null) {
            for (File file : files) {
                System.out.println(file.getName());
            }
        }

        // 删除文件(空目录才能删)
        // f.delete();
    }
}

注意 File 不能读写文件内容,只能操作路径。新项目建议用 Path(NIO.2)替代。

3. 字节流(InputStream / OutputStream)

字节流以字节(byte)为单位,适合处理二进制文件(图片、视频、zip)。

import java.io.*;

public class ByteStreamDemo {
    public static void main(String[] args) throws IOException {
        // 写字节到文件
        // try-with-resources 自动关闭流
        try (FileOutputStream fos = new FileOutputStream("data.bin")) {
            fos.write(72);          // 写一个字节
            fos.write(105);
            byte[] bytes = "Hello".getBytes();
            fos.write(bytes);
        }

        // 读字节
        try (FileInputStream fis = new FileInputStream("data.bin")) {
            int b;
            // read() 一次读一个字节,返回 -1 表示结束
            while ((b = fis.read()) != -1) {
                System.out.print((char) b + " ");
            }
            System.out.println();
        }

        // 一次读一个字节效率低,推荐用缓冲流或一次读一段
        try (FileInputStream fis = new FileInputStream("data.bin")) {
            byte[] buf = new byte[1024];
            int len = fis.read(buf);    // 返回实际读取的字节数
            String content = new String(buf, 0, len);
            System.out.println(content);
        }
    }
}

几个要点:

4. 字符流(Reader / Writer)

字符流以字符(char)为单位,自动处理编码,适合文本文件(txt、csv、json、html)。最常用 BufferedReader 逐行读:

import java.io.*;
import java.nio.charset.StandardCharsets;

public class ReaderDemo {
    public static void main(String[] args) throws IOException {
        // 字符流:专门处理文本文件(自动处理编码)
        // 写文本
        try (BufferedWriter bw = new BufferedWriter(
                new OutputStreamWriter(
                    new FileOutputStream("text.txt"),
                    StandardCharsets.UTF_8))) {
            bw.write("第一行");
            bw.newLine();                  // 跨平台的换行
            bw.write("第二行");
            bw.write("你好,Java IO!");
        }

        // 读文本:逐行读(最常用)
        try (BufferedReader br = new BufferedReader(
                new InputStreamReader(
                    new FileInputStream("text.txt"),
                    StandardCharsets.UTF_8))) {
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        }

        // 简化写法:FileReader/FileWriter(用默认编码,Java 11+ 可指定)
        try (BufferedReader br = new BufferedReader(
                new FileReader("text.txt", StandardCharsets.UTF_8))) {
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(">> " + line);
            }
        }
    }
}

字节流 vs 字符流的区别:

5. NIO.2:Path 与 Files(推荐!)

Java 7 引入的 Path + Files现代 IO 的首选——API 极简,自动管理资源:

import java.nio.file.*;
import java.nio.charset.StandardCharsets;
import java.io.IOException;
import java.util.*;

public class NioDemo {
    public static void main(String[] args) throws IOException {
        // NIO(Path + Files)是 Java 7+ 引入的现代 IO API
        // 比 File 更简洁、更安全、功能更强

        // 1. 一次性写文本(不用管流的关闭)
        Path p = Path.of("hello.txt");
        Files.writeString(p, "Hello, NIO!\n你好!");

        // 2. 一次性读文本
        String content = Files.readString(p);
        System.out.println(content);

        // 3. 读所有行(返回 List<String>)
        List<String> lines = Files.readAllLines(p);
        for (String line : lines) {
            System.out.println(line);
        }

        // 4. 复制、移动、删除文件
        Path target = Path.of("hello_copy.txt");
        Files.copy(p, target, StandardCopyOption.REPLACE_EXISTING);

        // Files.move(p, newPath);  // 移动/重命名
        // Files.delete(p);         // 删除

        // 5. 创建目录
        Files.createDirectories(Path.of("a/b/c"));

        // 6. 列出目录内容(Java 8 Stream)
        try (var stream = Files.list(Path.of("."))) {
            stream.filter(Files::isRegularFile)
                  .forEach(System.out::println);
        }

        // 7. 文件是否存在、大小
        System.out.println(Files.exists(p));   // true
        System.out.println(Files.size(p));     // 字节数
    }
}

对比传统 IO,NIO.2 的优势:

新项目几乎都用 NIO.2。传统 IO 只在维护老代码或框架内部见到。

6. 标准输入:Scanner

从控制台读用户输入,最简单的方式是 Scanner(基于 System.in):

import java.util.Scanner;

public class StdinDemo {
    public static void main(String[] args) {
        // Scanner:从标准输入(System.in)读用户输入
        Scanner sc = new Scanner(System.in);

        System.out.print("请输入你的名字: ");
        String name = sc.nextLine();          // 读一行
        System.out.println("你好, " + name);

        System.out.print("请输入你的年龄: ");
        if (sc.hasNextInt()) {
            int age = sc.nextInt();           // 读 int
            System.out.println("明年你 " + (age + 1) + " 岁");
        } else {
            System.out.println("不是有效的整数");
            sc.next();                        // 跳过错误的输入
        }

        System.out.print("输入三个数(空格分隔): ");
        int a = sc.nextInt();
        int b = sc.nextInt();
        int c = sc.nextInt();
        System.out.println("和 = " + (a + b + c));

        sc.close();    // Scanner 也是资源,要关闭
    }
}

7. IO 处理的最佳实践

小结

这一章你掌握了 Java IO 的核心:File、字节流、字符流、NIO.2(Files)、Scanner。新项目首选 NIO.2——简洁、安全、现代。下一篇我们看 Java 区别于其他语言的杀手锏——多线程并发。

← 上一篇 Java 异常处理

下一篇 Java 多线程

✈️💬