CodeGym /课程 /JAVA 25 SELF /文件读写:基础操作

文件读写:基础操作

JAVA 25 SELF
第 35 级 , 课程 2
可用

1. 整体读取文件

读取所有字节

有时需要把文件的全部内容一次性取出——原样不做解析,不管是图片、压缩包还是某种二进制格式。为此,Java 提供了 Files.readAllBytes(path) 方法。它返回字节数组(byte[]),也就是文件的原始数据,之后你可以按需使用。

import java.nio.file.*;

public class ReadBytesExample {
    public static void main(String[] args) throws Exception {
        Path path = Paths.get("example.txt");
        byte[] allBytes = Files.readAllBytes(path);
        System.out.println("文件长度(字节): " + allBytes.length);
    }
}

注意:如果文件很大(数 GB),这种方式可能导致内存问题——因为文件内容会一次性载入内存。

读取所有行

对于文本文件,有一种更“友好”的方式:Files.readAllLines(path)。它返回一个字符串列表(List<String>),其中每个元素对应文件中的一行(行分隔符会被自动处理)。

import java.nio.file.*;
import java.util.List;

public class ReadLinesExample {
    public static void main(String[] args) throws Exception {
        Path path = Paths.get("example.txt");
        List<String> lines = Files.readAllLines(path);

        for (String line : lines) {
            System.out.println(line);
        }
    }
}

重要:默认使用系统编码。如果你想显式指定编码(例如 UTF-8),请使用重载方法:

List<String> lines = Files.readAllLines(path, java.nio.charset.StandardCharsets.UTF_8);

示例:读取文件并打印到屏幕

让我们把它加入我们的迷你应用(例如“记事本”或“待办清单”):

import java.nio.file.*;
import java.util.List;

public class TodoReader {
    public static void main(String[] args) throws Exception {
        Path todoPath = Paths.get("todo.txt");
        if (Files.exists(todoPath)) {
            List<String> tasks = Files.readAllLines(todoPath);
            System.out.println("你今天的任务:");
            for (String task : tasks) {
                System.out.println("- " + task);
            }
        } else {
            System.out.println("未找到文件 todo.txt。请创建一个任务清单!");
        }
    }
}

2. 写入文件

写入字节数组

如果你已经有一个字节数组(例如序列化结果、图片、音频),可使用 Files.write(path, bytes)。该方法在文件不存在时创建文件,存在时覆盖写入。

import java.nio.file.*;

public class WriteBytesExample {
    public static void main(String[] args) throws Exception {
        Path path = Paths.get("output.bin");
        byte[] data = {1, 2, 3, 4, 5};
        Files.write(path, data);
        System.out.println("字节已写入文件 output.bin");
    }
}

写入字符串列表

对于文本文件,使用字符串列表更方便——每个元素会单独写入并带换行。

import java.nio.file.*;
import java.util.Arrays;
import java.util.List;

public class WriteLinesExample {
    public static void main(String[] args) throws Exception {
        Path path = Paths.get("todo.txt");
        List<String> tasks = Arrays.asList(
            "去买牛奶",
            "给奶奶打电话",
            "做 Java 作业"
        );
        Files.write(path, tasks);
        System.out.println("任务清单已写入 todo.txt");
    }
}

注意:默认会覆盖文件!如果文件已存在,旧内容会消失。(如何避免数据丢失——稍后说明。)

将字符串写入文件

如果只想写入一行——可以创建只包含一个元素的列表,或者使用 Files.write(path, string.getBytes())

import java.nio.file.*;

public class WriteStringExample {
    public static void main(String[] args) throws Exception {
        Path path = Paths.get("hello.txt");
        String message = "你好,Java!";
        Files.write(path, message.getBytes());
        System.out.println("字符串已写入 hello.txt");
    }
}

显式指定编码

为避免在处理中文、俄文等文本时出现“乱码”,请始终显式指定编码:

import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.List;

public class WriteLinesUtf8Example {
    public static void main(String[] args) throws Exception {
        Path path = Paths.get("hello.txt");
        List<String> lines = List.of("你好,世界!", "这是 Java。");
        Files.write(path, lines, StandardCharsets.UTF_8);
    }
}

3. 错误处理

在文件操作中,Java 可能会抛出 IOException。这通常表示在输入/输出层面“出了点问题”。原因很多:文件不存在、权限不足、磁盘已满或被占用,甚至可能是操作中途 U 盘被拔出等。

因此,读写文件的方法总是要求我们准备好处理这些情况。通常通过 try-catch 来完成:

import java.nio.file.*;
import java.util.List;
import java.io.IOException;

public class SafeReadExample {
    public static void main(String[] args) {
        Path path = Paths.get("todo.txt");
        try {
            List<String> lines = Files.readAllLines(path);
            System.out.println("文件内容:");
            for (String line : lines) {
                System.out.println(line);
            }
        } catch (IOException ex) {
            System.out.println("读取文件时出错: " + ex.getMessage());
        }
    }
}

为什么要这样?

try-catch 能把程序的潜在崩溃变成可控情形。没有文件——就友好地告知用户;系统拒绝访问——就指出问题;即使磁盘在操作中途“消失”,程序也不会以可怕的栈轨迹崩掉,而是至少给出正常的提示。换句话说:IOException 不是敌人,它只是 Java 告诉我们:“外部出了点状况,想个应对方案吧”的一种方式。

4. 实用示例

读取文件并打印内容

import java.nio.file.*;
import java.util.List;
import java.io.IOException;

public class PrintFileExample {
    public static void main(String[] args) {
        Path path = Paths.get("notes.txt");
        try {
            if (!Files.exists(path)) {
                System.out.println("未找到文件 notes.txt。");
                return;
            }
            List<String> lines = Files.readAllLines(path, java.nio.charset.StandardCharsets.UTF_8);
            System.out.println("notes.txt 的文件内容:");
            for (String line : lines) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("读取文件时出错: " + e.getMessage());
        }
    }
}

将字符串写入新文件

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

public class WriteFileExample {
    public static void main(String[] args) {
        Path path = Paths.get("greeting.txt");
        String content = "欢迎来到 Java IO 的世界!";
        try {
            Files.write(path, content.getBytes(StandardCharsets.UTF_8));
            System.out.println("字符串已写入文件 greeting.txt");
        } catch (IOException e) {
            System.out.println("写入文件时出错: " + e.getMessage());
        }
    }
}

将字符串列表写入文件

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

public class WriteListExample {
    public static void main(String[] args) {
        Path path = Paths.get("shopping.txt");
        List<String> items = List.of("面包", "牛奶", "奶酪");
        try {
            Files.write(path, items, StandardCharsets.UTF_8);
            System.out.println("购物清单已写入 shopping.txt");
        } catch (IOException e) {
            System.out.println("写入文件时出错: " + e.getMessage());
        }
    }
}

5. 关于流的简要说明

Files.readAllBytesFiles.readAllLinesFiles.write 都是“要么全有要么全无”的方式:要么把整个文件读入内存,要么一次性把所有内容写到磁盘。对小文件很方便,但对大文件就不太合适了(可能导致 OutOfMemoryError,或者在读取体积巨大的日志时“卡住”)。

处理大文件或需要逐行读取时,应使用流:

  • 文本:BufferedReaderBufferedWriter
  • 字节:InputStreamOutputStream

关于流我们会在接下来的讲座中详细讨论,这里先给一个小预告:

import java.nio.file.*;
import java.io.*;

public class BufferedReaderExample {
    public static void main(String[] args) {
        Path path = Paths.get("bigfile.txt");
        try (BufferedReader reader = Files.newBufferedReader(path)) {
            String line;
            while ((line = reader.readLine()) != null) {
                // 处理每一行
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("读取文件时出错: " + e.getMessage());
        }
    }
}

6. 实用细节

  • 覆盖文件:所有 Files.write 方法默认都会覆盖文件。若需追加到文件末尾,请使用附加选项(下一讲介绍)。
  • 编码:处理非 ASCII 文本时,请始终显式指定编码。这能避免输出“乱码”。一个不错的选择是 StandardCharsets.UTF_8
  • 路径:使用 Paths.get(...) 以保证跨平台性。不要手动硬编码斜杠(/\)。
  • 文件名:不要在文件名中使用非法字符(?*:<>| 等),尤其当你的代码需要在 Windows 上运行时。

7. 文件读写中的常见错误

错误 №1:未处理 IOException。 新手常常在没有 try-catch 的情况下直接调用 Files.readAllLines(path),一旦出现问题(文件不存在、无权限、磁盘损坏),程序就会崩溃。务必处理异常!

错误 №2:使用 readAllBytes/readAllLines 处理大文件。 如果文件有数百 MB 或数 GB,尝试一次性加载可能会“搞挂”你的程序。这类场景请使用流(BufferedReader)。

错误 №3:读/写文本时未指定编码。 如果不指定编码,在不同计算机和操作系统上的结果可能不一致。使用Cyrillic等字符时尤为明显。请显式使用 StandardCharsets.UTF_8 或所需编码。

错误 №4:误以为 File/Path 就是文件本身。FilePath 只是指向文件的“标识/引用”,并不是文件本身。仅仅创建对象并不会在磁盘上创建文件。要创建文件,请使用 Files.createFileFiles.write 等方法。

错误 №5:未关闭流(当你使用流时)。 如果手动使用流(如 BufferedReader),务必关闭它们(推荐使用 try-with-resources)。否则文件可能保持“锁定”状态,其他程序无法访问。

1
任务
JAVA 25 SELF, 第 35 级, 课程 2
已锁定
您的“秘密”文档占用多少空间? 📜
您的“秘密”文档占用多少空间? 📜
1
任务
JAVA 25 SELF, 第 35 级, 课程 2
已锁定
查看系统事件日志 💻
查看系统事件日志 💻
评论 (1)
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
ncksllpo 级别 44,Cherkasy,Ukraine
12 三月 2026
inputStream,outputStream