0

0

java如何读写本地文件内容 java文件操作的实用编程技巧

爱谁谁

爱谁谁

发布时间:2025-08-15 22:11:01

|

698人浏览过

|

来源于php中文网

原创

Java中文件读写核心是I/O流,常用BufferedReader/Writer、Scanner、Files工具类;处理大文件需流式读取避免内存溢出,推荐Files.lines()结合Stream;路径处理应使用Paths.get()确保跨平台兼容;文件操作优先选用java.nio.file.Files实现创建、删除、复制和移动。

java如何读写本地文件内容 java文件操作的实用编程技巧

Java中读写本地文件内容,核心在于理解I/O流的概念,并善用

java.io
java.nio.file
包提供的工具。从最基础的字节流、字符流,到现代的NIO.2 API,选择合适的方式能让文件操作既高效又安全。简单来说,就是把文件看作数据的入口或出口,然后用Java提供的“管道”去连接它们。

解决方案

在Java中进行文件读写,我们通常会用到以下几种方式,它们各有侧重,但目标都是一样的:把数据从文件里拿出来,或者把数据放进去。

读文件内容:

我个人在处理文本文件时,最常用的还是

BufferedReader
,因为它效率高,适合逐行读取大文件。配合
FileReader
使用,简直是文本处理的黄金搭档。

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

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Scanner;

public class FileReadWriteExample {

    public static void readFileWithBufferedReader(String filePath) {
        // try-with-resources 确保流自动关闭,这是Java里处理资源的好习惯
        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            String line;
            System.out.println("--- 使用 BufferedReader 读取文件 ---");
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.err.println("读取文件时发生错误: " + e.getMessage());
            // 实际应用中,这里可能需要更详细的错误日志或异常处理策略
        }
    }

    public static void readFileWithScanner(String filePath) {
        try (Scanner scanner = new Scanner(new FileReader(filePath))) {
            System.out.println("\n--- 使用 Scanner 读取文件 ---");
            while (scanner.hasNextLine()) {
                System.out.println(scanner.nextLine());
            }
        } catch (IOException e) {
            System.err.println("读取文件时发生错误: " + e.getMessage());
        }
    }

    public static void readFileWithFilesReadAllLines(String filePath) {
        try {
            System.out.println("\n--- 使用 Files.readAllLines 读取文件 ---");
            // 注意:Files.readAllLines 适合小文件,因为它会一次性把所有行加载到内存
            List lines = Files.readAllLines(Paths.get(filePath));
            for (String line : lines) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.err.println("读取文件时发生错误: " + e.getMessage());
        }
    }
}

写文件内容:

写入文件,我同样偏爱

BufferedWriter
,它有内部缓冲区,能减少实际的I/O操作次数,提升性能。
PrintWriter
则在需要格式化输出时非常方便。

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import java.util.List;

public class FileWriteExample {

    public static void writeFileWithBufferedWriter(String filePath, String content, boolean append) {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath, append))) {
            System.out.println("\n--- 使用 BufferedWriter 写入文件 ---");
            writer.write(content);
            writer.newLine(); // 写入一个换行符
            writer.write("这是新的一行。");
            System.out.println("内容已写入到 " + filePath);
        } catch (IOException e) {
            System.err.println("写入文件时发生错误: " + e.getMessage());
        }
    }

    public static void writeFileWithPrintWriter(String filePath, String content, boolean append) {
        try (PrintWriter writer = new PrintWriter(new FileWriter(filePath, append))) {
            System.out.println("\n--- 使用 PrintWriter 写入文件 ---");
            writer.println(content); // println 会自动添加换行符
            writer.printf("数字: %d, 字符串: %s%n", 123, "测试"); // 支持格式化输出
            System.out.println("内容已写入到 " + filePath);
        } catch (IOException e) {
            System.err.println("写入文件时发生错误: " + e.getMessage());
        }
    }

    public static void writeFileWithFilesWrite(String filePath, List lines, boolean append) {
        try {
            System.out.println("\n--- 使用 Files.write 写入文件 ---");
            // StandardOpenOption.APPEND 表示追加模式,CREATE 表示如果文件不存在则创建
            // 如果不指定 APPEND,默认是覆盖模式
            Files.write(Paths.get(filePath), lines, append ? StandardOpenOption.APPEND : StandardOpenOption.CREATE);
            System.out.println("内容已写入到 " + filePath);
        } catch (IOException e) {
            System.err.println("写入文件时发生错误: " + e.getMessage());
        }
    }

    public static void main(String[] args) {
        String testFilePath = "my_test_file.txt";
        String contentToWrite = "Hello, Java file operations!";
        List linesToWrite = Arrays.asList("Line 1 from Files.write", "Line 2 from Files.write");

        // 写入操作
        writeFileWithBufferedWriter(testFilePath, contentToWrite, false); // 覆盖写入
        writeFileWithPrintWriter(testFilePath, "这是一段用PrintWriter写入的内容。", true); // 追加写入
        writeFileWithFilesWrite(testFilePath, linesToWrite, true); // 追加写入

        // 读取操作
        readFileWithBufferedReader(testFilePath);
        readFileWithScanner(testFilePath);
        readFileWithFilesReadAllLines(testFilePath);
    }
}

上面这些代码片段,基本上涵盖了Java文件读写最常用的几种姿势。特别要注意

try-with-resources
,它能自动帮你关闭流,避免资源泄露,这是个非常棒的特性,能省去不少麻烦。

Java文件操作中如何高效处理大文件,避免内存溢出?

处理大文件时,最怕的就是内存溢出(OutOfMemoryError)。我个人就遇到过好几次,尤其是在用

Files.readAllLines()
或者一次性读入所有字节时,如果文件太大,内存根本吃不消。所以,关键在于“流式处理”和“懒加载”。

避免内存溢出的核心策略:

  1. 逐行读取/分块处理: 不要试图一次性把整个文件读进内存。无论是
    BufferedReader
    还是
    Scanner
    ,它们都是逐行读取的,每次只加载一行到内存,处理完一行再读下一行。对于二进制文件,可以分块(比如每次读几KB或几十KB)读取。
  2. Java 8的
    Files.lines()
    这是个非常优雅的解决方案。它返回一个
    Stream
    ,这个流是“懒加载”的。也就是说,只有当你真正遍历这个Stream时,它才会去读取文件内容,而且也是逐行读取,不会一次性加载所有行。这在结合Stream API进行数据处理时尤其强大。

示例:使用

Files.lines()
处理大文件

doxygen 官方手册
doxygen 官方手册

doxygen是一款好用的程序员辅助工具,它可以让程序添加批添代码更加简单轻松,兼容C++、 C、Java、 Objective-C、Python等主流编程语言,小编提供的doxygen中文手册包含了基本介绍、语法技巧以及进阶技巧等内容,可以让你快速上手操作,有需要的欢迎下载。 基本介绍 Doxygen已经支持生成ANSI编码的chm目录文件(index.hhc)!Doxygen通常是用作生成英文文档的,生成中文文档需要修改输入和输出的码制,这样可以改变解析方式,生成中文文档。但是,你必须意识 到,Dox

下载
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Stream;

public class LargeFileReader {

    public static void processLargeFileWithStream(String filePath) {
        System.out.println("\n--- 使用 Files.lines() 处理大文件 ---");
        AtomicLong lineCount = new AtomicLong(0); // 用于计数,确保不是一次性加载
        try (Stream lines = Files.lines(Paths.get(filePath))) {
            lines.forEach(line -> {
                // 这里可以对每一行进行处理,比如解析、过滤、转换等
                // System.out.println("处理行: " + line); // 实际处理时可能不会打印,以防控制台输出过多
                lineCount.incrementAndGet();
                if (lineCount.get() % 100000 == 0) { // 每处理10万行打印一次进度
                    System.out.println("已处理 " + lineCount.get() + " 行...");
                }
            });
            System.out.println("文件处理完毕,总行数: " + lineCount.get());
        } catch (IOException e) {
            System.err.println("处理大文件时发生错误: " + e.getMessage());
        }
    }

    public static void main(String[] args) {
        // 假设有一个很大的文件 large_data.txt
        // 为了演示,我们先创建一个模拟的大文件
        String largeFilePath = "large_data.txt";
        createMockLargeFile(largeFilePath, 1000000); // 创建一个包含100万行的大文件

        processLargeFileWithStream(largeFilePath);
    }

    // 辅助方法:创建一个模拟的大文件
    private static void createMockLargeFile(String filePath, int lines) {
        System.out.println("正在创建模拟大文件 " + filePath + ",包含 " + lines + " 行...");
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) {
            for (int i = 0; i < lines; i++) {
                writer.write("This is line number " + (i + 1) + " of the large file.");
                writer.newLine();
            }
            System.out.println("模拟大文件创建完成。");
        } catch (IOException e) {
            System.err.println("创建模拟大文件时发生错误: " + e.getMessage());
        }
    }
}

Files.lines()
的优势在于它返回的是一个
Stream
,可以方便地与Java 8的函数式编程结合,进行过滤、映射、聚合等操作,而无需一次性加载所有数据。这对于日志分析、大数据预处理等场景非常实用。

文件路径处理有哪些常见陷阱?如何确保跨平台兼容性?

文件路径这东西,看着简单,坑可不少。我个人就经常在Windows和Linux之间切换开发环境,每次都要特别注意路径分隔符的问题。Windows用反斜杠

\
,Linux/macOS用正斜杠
/
,如果硬编码路径,那妥妥的会出问题。

常见陷阱:

  1. 路径分隔符: 这是最常见的,也是最容易忽视的。
    C:\Users\John\file.txt
    在Windows上可以,但放到Linux上就会报错。
  2. 相对路径与绝对路径: 相对路径是相对于当前程序运行目录的,如果程序启动目录变了,相对路径就会失效。绝对路径虽然稳定,但硬编码到代码里又不够灵活。
  3. 特殊字符: 文件名或路径中包含空格、中文、特殊符号等,处理不当也可能引发问题。

确保跨平台兼容性的策略:

  1. 使用
    java.nio.file.Paths
    Path
    这是Java 7引入的NIO.2 API,强烈推荐使用。它抽象了文件路径,内部会自动处理平台差异。
    • Paths.get("dir", "subdir", "file.txt")
      :这样构建路径,Java会自动使用正确的路径分隔符。
    • Path.resolve()
      :用于拼接路径。
    • Path.normalize()
      :规范化路径,处理
      ..
      .
  2. 使用
    File.separator
    如果你还在用老旧的
    java.io.File
    ,可以用
    File.separator
    来获取当前操作系统的路径分隔符。但这不如
    Paths.get()
    来得优雅和彻底。
  3. 获取当前工作目录:
    System.getProperty("user.dir")
    可以获取当前Java应用程序的运行目录,这对于构建相对路径很有用,但要小心,这个目录是JVM启动时的目录,不一定是jar包所在的目录。
  4. 避免硬编码: 尽量通过配置、命令行参数或者用户输入来获取文件路径,而不是直接写死在代码里。

示例:跨平台路径处理

import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;

public class FilePathCompatibility {

    public static void main(String[] args) {
        // 1. 使用 File.separator (老方法,但仍可用)
        String fileName = "my_document.txt";
        String dirName = "data";
        String fullPathOld = dirName + File.separator + fileName;
        System.out.println("使用 File.separator 构建的路径: " + fullPathOld);
        System.out.println("当前系统路径分隔符: '" + File.separator + "'");

        // 2. 推荐:使用 java.nio.file.Paths
        Path path = Paths.get("reports", "2023", "summary.csv");
        System.out.println("\n使用 Paths.get() 构建的路径: " + path);

        Path anotherPath = Paths.get("/home", "user", "documents"); // 绝对路径
        System.out.println("使用 Paths.get() 构建的绝对路径: " + anotherPath);

        // 拼接路径
        Path baseDir = Paths.get("temp");
        Path finalPath = baseDir.resolve("logs").resolve("app.log");
        System.out.println("使用 resolve() 拼接的路径: " + finalPath);

        // 规范化路径 (处理 .. 和 .)
        Path unnormalizedPath = Paths.get("/a/./b/../c");
        Path normalizedPath = unnormalizedPath.normalize();
        System.out.println("非规范化路径: " + unnormalizedPath);
        System.out.println("规范化路径: " + normalizedPath);

        // 3. 获取当前工作目录
        String userDir = System.getProperty("user.dir");
        System.out.println("\n当前用户工作目录: " + userDir);
        Path relativePathFromUserDir = Paths.get(userDir, "config", "settings.properties");
        System.out.println("基于用户工作目录的相对路径: " + relativePathFromUserDir);

        // 检查文件是否存在
        File someFile = new File(fullPathOld);
        if (someFile.exists()) {
            System.out.println(fullPathOld + " 存在。");
        } else {
            System.out.println(fullPathOld + " 不存在。");
        }
    }
}

总的来说,尽量拥抱

java.nio.file
包,它在处理文件路径和文件系统操作方面提供了更强大、更灵活、更跨平台的API。

如何在Java中进行文件或目录的创建、删除、移动和复制?

除了读写文件内容,文件系统本身的结构操作也同样重要。比如,程序运行时可能需要创建日志目录,或者在处理完文件后将其移动到存档目录。

java.io.File
类提供了一些基本操作,但Java 7引入的
java.nio.file.Files
工具类则提供了更丰富、更健壮的功能,我个人更推荐使用
Files

文件和目录操作:

  1. 创建:
    • Files.createFile(Path path)
      :创建新文件。如果文件已存在,会抛出
      FileAlreadyExistsException
    • Files.createDirectory(Path dir)
      :创建新目录。如果父目录不存在,会抛出
      NoSuchFileException
    • Files.createDirectories(Path dir)
      :创建目录,包括所有必需但不存在的父目录。这是我最常用的创建目录的方法,非常省心。
  2. 删除:
    • Files.delete(Path path)
      :删除文件或空目录。如果文件不存在或目录不为空,会抛出异常。
    • Files.deleteIfExists(Path path)
      :删除文件或空目录,如果文件不存在则不执行任何操作,也不会抛出异常。这个方法更“温柔”一些。
  3. 复制:
    • Files.copy(Path source, Path target, CopyOption... options)
      :复制文件或目录。
      options
      可以指定
      StandardCopyOption.REPLACE_EXISTING
      (覆盖目标文件)、
      StandardCopyOption.COPY_ATTRIBUTES
      (复制文件属性)等。
  4. 移动/重命名:
    • Files.move(Path source, Path target, CopyOption... options)
      :移动文件或目录。也可以用来重命名文件(如果目标路径只是文件名不同)。
      options
      同样可以指定
      StandardCopyOption.REPLACE_EXISTING

示例:文件和目录操作

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

public class FileDirectoryOperations {

    public static void main(String[] args) {
        Path baseDir = Paths.get("my_app_data");
        Path subDir = baseDir.resolve("logs");
        Path file1 = subDir.resolve("app_log.txt");
        Path file2 = subDir.resolve("error_log.txt");
        Path copiedFile = Paths.get("copied_app_log.txt");
        Path movedFile = Paths.get("moved_error_log.txt");

        try {
            // 1. 创建目录
            System.out.println("--- 创建目录 ---");
            if (!Files.exists(baseDir)) {
                Files.createDirectory(baseDir); // 创建my_app_data
                System.out.println("目录 " + baseDir + " 已创建。");
            }
            if (!Files.exists(subDir)) {
                Files.createDirectories(subDir); // 创建my_app_data/logs,即使my_app_data不存在也会一并创建
                System.out.println("目录 " + subDir + " 已创建。");
            }

            // 2. 创建文件
            System.out.println("\n--- 创建文件 ---");
            if (!Files.exists(file1)) {
                Files.createFile(file1);
                System.out.println("文件 " + file1 + " 已创建。");
            }
            if (!Files.exists(file2)) {
                Files.createFile(file2);
                System.out.println("文件 " + file2 + " 已创建。");
            }

            // 3. 写入一些内容到文件,方便后续操作
            Files.write(file1, "这是app日志内容。".getBytes());
            Files.write(file2, "这是error日志内容。".getBytes());

            // 4. 复制文件
            System.out.println("\n--- 复制文件 ---");
            // 复制 file1 到 copiedFile,如果目标文件存在则覆盖
            Files.copy(file1, copiedFile, StandardCopyOption.REPLACE_EXISTING);
            System.out.println("文件 " + file1 + " 已复制到 " + copiedFile);

            // 5. 移动/重命名文件
            System.out.println("\n--- 移动/重命名文件 ---");
            // 移动 file2 到 movedFile,如果目标文件存在则覆盖
            Files.move(file2, movedFile, StandardCopyOption.REPLACE_EXISTING);
            System.out.println("文件 " + file2 + " 已移动到 " + movedFile);

热门AI工具

更多
DeepSeek
DeepSeek

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

豆包大模型
豆包大模型

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

通义千问
通义千问

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

腾讯元宝
腾讯元宝

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

文心一言
文心一言

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

讯飞写作
讯飞写作

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

即梦AI
即梦AI

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

ChatGPT
ChatGPT

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

相关专题

更多
string转int
string转int

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

443

2023.08.02

数据库Delete用法
数据库Delete用法

数据库Delete用法:1、删除单条记录;2、删除多条记录;3、删除所有记录;4、删除特定条件的记录。更多关于数据库Delete的内容,大家可以访问下面的文章。

275

2023.11.13

drop和delete的区别
drop和delete的区别

drop和delete的区别:1、功能与用途;2、操作对象;3、可逆性;4、空间释放;5、执行速度与效率;6、与其他命令的交互;7、影响的持久性;8、语法和执行;9、触发器与约束;10、事务处理。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

213

2023.12.29

windows查看端口占用情况
windows查看端口占用情况

Windows端口可以认为是计算机与外界通讯交流的出入口。逻辑意义上的端口一般是指TCP/IP协议中的端口,端口号的范围从0到65535,比如用于浏览网页服务的80端口,用于FTP服务的21端口等等。怎么查看windows端口占用情况呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

760

2023.07.26

查看端口占用情况windows
查看端口占用情况windows

端口占用是指与端口关联的软件占用端口而使得其他应用程序无法使用这些端口,端口占用问题是计算机系统编程领域的一个常见问题,端口占用的根本原因可能是操作系统的一些错误,服务器也可能会出现端口占用问题。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1128

2023.07.27

windows照片无法显示
windows照片无法显示

当我们尝试打开一张图片时,可能会出现一个错误提示,提示说"Windows照片查看器无法显示此图片,因为计算机上的可用内存不足",本专题为大家提供windows照片无法显示相关的文章,帮助大家解决该问题。

799

2023.08.01

windows查看端口被占用的情况
windows查看端口被占用的情况

windows查看端口被占用的情况的方法:1、使用Windows自带的资源监视器;2、使用命令提示符查看端口信息;3、使用任务管理器查看占用端口的进程。本专题为大家提供windows查看端口被占用的情况的相关的文章、下载、课程内容,供大家免费下载体验。

454

2023.08.02

windows无法访问共享电脑
windows无法访问共享电脑

在现代社会中,共享电脑是办公室和家庭的重要组成部分。然而,有时我们可能会遇到Windows无法访问共享电脑的问题。这个问题可能会导致数据无法共享,影响工作和生活的正常进行。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2354

2023.08.08

php中文乱码如何解决
php中文乱码如何解决

本文整理了php中文乱码如何解决及解决方法,阅读节专题下面的文章了解更多详细内容。

1

2026.01.28

热门下载

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

精品课程

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

共23课时 | 2.9万人学习

C# 教程
C# 教程

共94课时 | 7.7万人学习

Java 教程
Java 教程

共578课时 | 52.1万人学习

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

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