0

0

java怎样操作文件进行读写操作 java文件读写的详细操作教程​

雪夜

雪夜

发布时间:2025-08-02 16:12:01

|

586人浏览过

|

来源于php中文网

原创

java中文件读写本质是数据流的进出,主要通过传统io和nio.2两种方式实现;传统io基于流,使用fileinputstream/filereader和fileoutputstream/filewriter配合缓冲流进行读写,适合简单任务,而nio.2基于path和files工具类,提供更现代、高效、功能丰富的api,推荐用于现代开发;1. 读写文本文件应优先使用bufferedreader/bufferedwriter或nio.2的files.readstring/writestring,并明确指定standardcharsets.utf_8编码避免乱码;2. 必须使用try-with-resources确保流自动关闭,防止资源泄露;3. 性能优化关键是使用缓冲流减少i/o操作,避免频繁flush,对大文件可考虑内存映射;4. 常见陷阱包括未关闭流、编码不一致、直接使用非缓冲流和路径处理不当;5. nio.2支持高级操作如文件复制移动(files.copy/move)、属性读取(files.readattributes)、目录遍历(files.walk)、临时文件创建和文件系统监控(watchservice),功能更强大且代码更简洁;因此,对于新项目应优先选择nio.2,传统io适用于简单场景或维护旧代码。

java怎样操作文件进行读写操作 java文件读写的详细操作教程​

Java中操作文件进行读写,本质上就是数据流的进出。你可以想象成给文件开辟一个通道,然后把数据倒进去(写),或者从里面舀出来(读)。这其中,Java提供了好几套API来做这件事,从经典的IO流到后来更现代的NIO.2,各有侧重,但核心都是围绕着数据的传输。

解决方案

要进行文件读写,我们通常会用到字节流(处理所有类型数据)或字符流(专门处理文本数据)。对于文本文件,我个人更倾向于使用字符流,因为它能更好地处理字符编码问题。

写入文件:

立即学习Java免费学习笔记(深入)”;

最常见且推荐的做法是使用

FileWriter
配合
BufferedWriter
来写文本,或者
FileOutputStream
配合
BufferedOutputStream
来写二进制数据。
BufferedWriter
BufferedOutputStream
能有效提升性能,因为它不会每次写入都直接操作硬盘,而是先写入内存缓冲区,满了或者手动刷新时才写入。

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.FileOutputStream;
import java.io.BufferedOutputStream;
import java.nio.charset.StandardCharsets; // 推荐指定编码

public class FileWriteExample {

    public static void main(String[] args) {
        // 写入文本文件
        String textContent = "你好,世界!\n这是Java文件写入的示例。\n再来一行。";
        try (BufferedWriter writer = new BufferedWriter(new FileWriter("myTextFile.txt", StandardCharsets.UTF_8))) {
            // true 表示追加模式,如果文件不存在则创建
            // 默认是覆盖模式。这里我直接在FileWriter里指定了编码和追加模式
            // 对于FileWriter直接指定Charset,需要Java 11+ 或者使用OutputStreamWriter
            // 更标准的方式是:
            // new BufferedWriter(new OutputStreamWriter(new FileOutputStream("myTextFile.txt", true), StandardCharsets.UTF_8))
            // 不过对于简单的文本写入,FileWriter(String fileName, boolean append) 配合默认编码也行
            // 但为了编码安全,我更推荐明确指定。
            // 简单起见,我这里先用一个常见的FileWriter构造器,但心里要知道编码问题。

            // 实际上,更推荐的文本写入方式是NIO.2的Files.writeString
            // Files.writeString(Path.of("myTextFileNIO.txt"), textContent, StandardOpenOption.CREATE, StandardOpenOption.APPEND);
            // 这里我们先专注于传统IO

            writer.write(textContent);
            System.out.println("文本内容已写入 myTextFile.txt");
        } catch (IOException e) {
            System.err.println("写入文本文件时发生错误: " + e.getMessage());
        }

        // 写入二进制文件 (例如,一个简单的字节序列)
        byte[] binaryData = {0x01, 0x02, 0x03, 0x04, 0x05, 0x0A, 0x0B};
        try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("myBinaryFile.bin"))) {
            bos.write(binaryData);
            System.out.println("二进制内容已写入 myBinaryFile.bin");
        } catch (IOException e) {
            System.err.println("写入二进制文件时发生错误: " + e.getMessage());
        }
    }
}

读取文件:

读取文件与写入类似,使用

FileReader
配合
BufferedReader
读取文本,或
FileInputStream
配合
BufferedInputStream
读取二进制。
BufferedReader
提供了按行读取的方法,非常方便。

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.BufferedInputStream;
import java.nio.charset.StandardCharsets; // 推荐指定编码

public class FileReadExample {

    public static void main(String[] args) {
        // 读取文本文件
        System.out.println("--- 读取文本文件 ---");
        try (BufferedReader reader = new BufferedReader(new FileReader("myTextFile.txt", StandardCharsets.UTF_8))) {
            // 同样,这里如果需要严格控制编码,应该用 InputStreamReader
            // new BufferedReader(new InputStreamReader(new FileInputStream("myTextFile.txt"), StandardCharsets.UTF_8))
            // 不过FileReader(String fileName, Charset charset) 也是Java 11+ 的便利方法

            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
            System.out.println("文本文件读取完毕。");
        } catch (IOException e) {
            System.err.println("读取文本文件时发生错误: " + e.getMessage());
        }

        // 读取二进制文件
        System.out.println("\n--- 读取二进制文件 ---");
        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("myBinaryFile.bin"))) {
            int byteRead;
            System.out.print("读取到的二进制数据 (十进制): ");
            while ((byteRead = bis.read()) != -1) {
                System.out.print(byteRead + " ");
            }
            System.out.println("\n二进制文件读取完毕。");
        } catch (IOException e) {
            System.err.println("读取二进制文件时发生错误: " + e.getMessage());
        }
    }
}

核心要点:

  • try-with-resources
    这是Java 7引入的特性,它能确保在
    try
    块结束时,资源(如文件流)会被自动关闭,即使发生异常也不例外。这是处理文件IO的最佳实践,避免了资源泄露。
  • 缓冲流: 总是优先使用
    BufferedInputStream
    /
    BufferedOutputStream
    BufferedReader
    /
    BufferedWriter
    来包装底层的
    FileInputStream
    /
    FileOutputStream
    FileReader
    /
    FileWriter
    。它们通过内部缓冲区减少了实际的I/O操作次数,大大提高了性能。
  • 编码: 处理文本文件时,明确指定字符编码(如
    StandardCharsets.UTF_8
    )至关重要,否则在不同操作系统或环境中可能会出现乱码问题。

Java文件读写,传统IO与NIO.2有什么区别?我该如何选择?

这确实是个好问题,常常让人纠结。简单来说,传统IO(

java.io
包)是基于流(Stream)的,面向字节或字符,而NIO.2(
java.nio.file
包,从Java 7开始)则是基于通道(Channel)和缓冲区(Buffer),并且更注重文件系统操作。

传统IO (

java.io
):

  • 面向流: 数据从一个源流向一个目的地,就像水流一样。
  • 阻塞I/O: 当你调用一个读写方法时,线程会一直等待,直到数据完全读取或写入完成。这在处理大量并发I/O时可能会成为瓶颈。
  • 字节/字符: 区分处理原始字节和处理字符(需要考虑编码)。
  • 优点: 概念直观,API相对简单,对于顺序读写小文件或简单任务非常易用。很多老项目和教程都基于它。
  • 缺点: 性能可能不如NIO.2,特别是对于非阻塞操作和高并发场景。文件系统操作(如复制、移动、获取属性)相对分散且不够原子化。

NIO.2 (

java.nio.file
):

  • 面向通道和缓冲区: 数据通过通道在缓冲区中流动,你可以更精细地控制数据的读写。
  • 非阻塞I/O(NIO): 虽然NIO.2的
    Files
    类方法大多是阻塞的,但整个NIO框架(
    java.nio
    )支持非阻塞I/O,允许一个线程管理多个I/O通道,提高并发效率。对于文件操作,NIO.2更多是提供了更现代、功能更丰富的API。
  • 路径 (
    Path
    ) 为核心:
    引入了
    Path
    对象来代表文件或目录的路径,比
    File
    对象更强大,支持更丰富的路径操作和文件系统语义。
  • 更丰富的文件系统操作: 提供了
    Files
    工具类,包含大量静态方法用于复制、移动、删除文件/目录,读取/设置文件属性,创建符号链接,遍历目录树等,许多操作都支持原子性。
  • 优点: 性能通常更好,尤其是在处理大文件或需要更高级文件系统操作时。API设计更现代,功能更强大,更健壮(例如原子操作)。
  • 缺点: 对于初学者来说,概念可能比传统IO稍微复杂一点。

我该如何选择?

这取决于你的具体需求和项目的Java版本。

  • 如果你是初学者,或者只需要进行简单的文件读写,且对性能要求不是极致: 传统IO(尤其是结合缓冲流和
    try-with-resources
    )仍然是一个非常好的选择,它简单易懂,足以应对大部分日常任务。
  • 如果你在Java 7及更高版本上开发,并且:
    • 需要处理大文件,追求更好的I/O性能。
    • 需要进行复杂的路径操作、文件系统遍历。
    • 需要原子化的文件操作(如移动文件,确保要么成功要么不发生)。
    • 需要获取或设置更丰富的文件属性。
    • 需要监控文件系统变化(
      WatchService
      )。
    • 那么,NIO.2无疑是更优的选择。它的
      Files
      类提供了许多一行代码就能完成复杂任务的便捷方法,比如
      Files.readAllLines()
      Files.writeString()
      等,用起来非常舒服。

在我看来,对于现代Java应用开发,NIO.2的

java.nio.file
包是首选。它不仅提供了更强大的功能,而且代码通常更简洁、更安全。但了解传统IO也很有必要,毕竟很多遗留代码和库还在使用它。

处理Java文件读写时,有哪些常见的陷阱和性能优化技巧?

文件I/O操作是个双刃剑,用不好很容易掉坑里,甚至影响整个应用的性能和稳定性。我个人在处理文件时,踩过不少坑,也总结了一些经验。

常见的陷阱:

  1. 不关闭流(Resource Leaks): 这是最最常见的错误!如果文件流没有正确关闭,会导致文件句柄泄露,文件被锁定,无法删除或修改,最终可能耗尽系统资源。

    • 避免方法: 永远使用
      try-with-resources
      语句。它能保证流在
      try
      块结束后自动关闭,即使发生异常。这是Java 7+ 的福音。
    • 反例(老旧且危险):
      finally
      块里手动关闭,而且还要判断是否为
      null
      ,再包一层
      try-catch
      处理关闭时的异常,代码冗长且容易出错。
  2. 字符编码问题(乱码): 尤其是在跨平台或处理不同来源的文本文件时,如果读写时使用的编码不一致,就会出现乱码。

    Pixso AI
    Pixso AI

    Pixso AI是一款智能生成设计稿工具,通过AI一键实现文本输入到设计稿生成。

    下载
    • 避免方法: 明确指定字符编码,例如
      StandardCharsets.UTF_8
      。对于
      FileReader
      /
      FileWriter
      ,在Java 11+ 可以直接在构造函数中指定
      Charset
      ;对于老版本或更通用的场景,使用
      InputStreamReader
      /
      OutputStreamWriter
      来包装字节流并指定编码。
  3. 不使用缓冲流(性能低下): 直接使用

    FileInputStream
    /
    FileOutputStream
    FileReader
    /
    FileWriter
    进行单字节/单字符的读写,效率非常低,因为每次读写都可能涉及昂贵的磁盘I/O操作。

    • 避免方法: 始终使用
      BufferedInputStream
      /
      BufferedOutputStream
      BufferedReader
      /
      BufferedWriter
      来包装底层流。它们会使用一个内存缓冲区,批量读写数据,显著减少实际的磁盘访问次数。
  4. 文件路径问题: 相对路径在不同执行环境下可能解析到不同的位置;路径中包含特殊字符(如空格、中文)在某些旧系统或API下可能出问题。

    • 避免方法: 尽量使用绝对路径,或者使用
      Path
      对象(NIO.2)来构建和解析路径,它对不同操作系统的路径分隔符有更好的兼容性。
  5. 权限不足或文件不存在: 尝试读写一个不存在的文件,或者没有足够权限的文件,会抛出

    IOException
    (通常是
    FileNotFoundException
    AccessDeniedException
    )。

    • 避免方法: 提前检查文件是否存在或创建文件(
      Files.exists()
      ,
      Files.createFile()
      ),并捕获并处理
      IOException

性能优化技巧:

  1. 使用缓冲流: (再次强调,因为太重要了)这是最基本也是最有效的优化手段。

    // 示例:使用缓冲流复制文件
    try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("source.txt"));
         BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("destination.txt"))) {
        byte[] buffer = new byte[8192]; // 8KB 缓冲区
        int bytesRead;
        while ((bytesRead = bis.read(buffer)) != -1) {
            bos.write(buffer, 0, bytesRead);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
  2. 利用NIO.2的便利方法: 对于一些常见的读写操作,

    Files
    类提供了高度优化的静态方法,它们内部通常已经处理了缓冲和资源关闭。

    • Files.readAllBytes(Path path)
      :读取所有字节到一个字节数组。适合小文件。
    • Files.readAllLines(Path path, Charset cs)
      :读取所有行到一个
      List
      。适合小文本文件。
    • Files.write(Path path, byte[] bytes, OpenOption... options)
      :写入字节数组。
    • Files.writeString(Path path, CharSequence csq, Charset cs, OpenOption... options)
      :写入字符串。
    • Files.copy(Path source, Path target, CopyOption... options)
      :高效复制文件。
    • 这些方法通常比手动构建流链更简洁且性能更优。
  3. 内存映射文件(Memory-Mapped Files,NIO

    MappedByteBuffer
    ): 对于非常大的文件(GB级别),如果需要随机访问或频繁读写,内存映射是一种高级且高效的技术。它将文件的一部分或全部映射到JVM的内存中,操作内存就像操作文件一样,避免了传统的I/O系统调用开销。

    • 适用场景: 数据库系统、大型日志文件处理等。
    • 注意: 涉及Direct Buffer,内存管理需要更小心,不当使用可能导致内存泄露或OOM。
  4. 批量写入: 如果你需要写入大量小块数据,尽量将它们聚合成更大的块再写入,而不是每次写入一小部分。例如,在循环中构建一个

    StringBuilder
    ,然后一次性
    writer.write(stringBuilder.toString())

  5. 避免不必要的刷新(

    flush()
    ): 频繁调用
    flush()
    会强制缓冲区内容写入磁盘,这会降低性能。只有在确实需要确保数据立即写入磁盘(例如,在关键操作后)时才调用它。
    try-with-resources
    会在关闭时自动
    flush

除了基本读写,Java还能对文件进行哪些高级操作?

Java在文件系统操作方面提供了相当丰富的功能,尤其是在NIO.2(

java.nio.file
包)中,这些操作变得更加强大和直观。这远不止简单的读写,更深入到了文件系统层面的交互。

  1. 文件和目录的创建、删除、移动与复制:

    • Files.createFile(Path path)
      : 创建一个空文件。
    • Files.createDirectory(Path dir)
      : 创建一个目录。
    • Files.createDirectories(Path dir)
      : 创建多级目录(如果父目录不存在也会创建)。
    • Files.delete(Path path)
      : 删除文件或空目录。
    • Files.deleteIfExists(Path path)
      : 删除文件或空目录,如果不存在则不抛异常。
    • Files.copy(Path source, Path target, CopyOption... options)
      : 复制文件或目录。可以指定
      StandardCopyOption.REPLACE_EXISTING
      (覆盖)、
      StandardCopyOption.COPY_ATTRIBUTES
      (复制文件属性)等。
    • Files.move(Path source, Path target, CopyOption... options)
      : 移动文件或目录,支持原子移动(
      StandardCopyOption.ATOMIC_MOVE
      )。
  2. 文件属性操作:

  3. 文件系统遍历和查找:

    • Files.walk(Path start, int maxDepth, FileVisitOption... options)
      : 递归遍历目录树,返回一个
      Stream
      ,非常适合结合Stream API进行文件过滤、查找等操作。
    • Files.find(Path start, int maxDepth, BiPredicate matcher, FileVisitOption... options)
      : 更强大的查找功能,可以自定义匹配规则。
    • Files.list(Path dir)
      : 列出目录下的直接子文件和子目录,返回一个
      Stream
  4. 临时文件和目录:

    • Files.createTempFile(String prefix, String suffix, FileAttribute... attrs)
      : 创建一个唯一的临时文件。
    • Files.createTempDirectory(String prefix, FileAttribute... attrs)
      : 创建一个唯一的临时目录。
    • 这些在需要临时存储数据,用完即焚的场景非常有用。
  5. 符号链接和硬链接:

    • Files.createSymbolicLink(Path link, Path target, FileAttribute... attrs)
      : 创建一个符号链接(快捷方式)。
    • Files.createLink(Path link, Path existing)
      : 创建一个硬链接。
    • Files.isSymbolicLink(Path path)
      : 判断是否是符号链接。
  6. 文件系统监控(

    WatchService
    ):

    • 这是NIO.2中一个非常酷的功能,允许你注册一个目录,然后监听该目录下的文件创建、修改、删除等事件。
    • 适用于需要实时响应文件系统变化的场景,比如日志分析、文件同步服务等。
    • 虽然实现起来比其他API稍微复杂一些,因为它涉及到线程和事件循环,但它提供了强大的非阻塞监控能力。

这些高级操作让Java在文件系统层面的控制力大大增强,使得开发者可以编写出更健壮、更灵活的文件处理程序。在我的日常开发中,NIO.2的

Files
Path
类几乎成了处理文件时的首选,它们确实让很多原本繁琐的任务变得异常简洁和高效。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

463

2023.08.02

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

237

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

458

2024.03.01

resource是什么文件
resource是什么文件

Resource文件是一种特殊类型的文件,它通常用于存储应用程序或操作系统中的各种资源信息。它们在应用程序开发中起着关键作用,并在跨平台开发和国际化方面提供支持。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

158

2023.12.20

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

320

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

212

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1502

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

625

2023.11.24

C++ 设计模式与软件架构
C++ 设计模式与软件架构

本专题深入讲解 C++ 中的常见设计模式与架构优化,包括单例模式、工厂模式、观察者模式、策略模式、命令模式等,结合实际案例展示如何在 C++ 项目中应用这些模式提升代码可维护性与扩展性。通过案例分析,帮助开发者掌握 如何运用设计模式构建高质量的软件架构,提升系统的灵活性与可扩展性。

14

2026.01.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 3万人学习

C# 教程
C# 教程

共94课时 | 7.9万人学习

Java 教程
Java 教程

共578课时 | 53.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号