java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java文件与IO流

Java文件与IO流详细攻略

作者:无名-CODING

文章详细介绍了Java中的IO流,包括字节流和字符流的区别,如何使用File类进行文件操作,以及如何进行高效的文件读写,文章还讨论了字符编码的重要性,如何避免常见的编码问题,以及如何使用现代的NIO.2 API进行文件操作,感兴趣的朋友跟随小编一起看看吧

导读:为什么要学 IO 流?

基石:File 类(文件与目录)

java.io.File 不是“文件内容”,而是“文件或目录的路径抽象”。常见用法:

import java.io.File;
public class FileBasicsDemo {
    public static void main(String[] args) {
        // 1) 路径与构造
        File file = new File("D:/IO/hello.txt"); // 建议使用 / 或者使用 Paths 构建
        File dir  = new File("D:/IO/sub");
        // 2) 基本信息
        System.out.println(file.getAbsolutePath());
        System.out.println(file.getName());
        System.out.println(file.exists());
        System.out.println(file.isFile());
        System.out.println(file.isDirectory());
        // 3) 创建目录/文件
        if (!dir.exists()) {
            boolean ok = dir.mkdirs(); // 递归创建目录
            System.out.println("mkdirs: " + ok);
        }
        // 创建新文件(若父目录不存在会失败)
        try {
            if (!file.exists()) {
                boolean created = file.createNewFile();
                System.out.println("createNewFile: " + created);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 4) 遍历目录
        File root = new File("D:/IO");
        File[] children = root.listFiles();
        if (children != null) {
            for (File f : children) {
                System.out.println((f.isDirectory() ? "[DIR] " : "[FILE]") + f.getName());
            }
        }
    }
}

提示:在 Windows 上用 "D:/path/file.txt" 更稳妥,避免 \\ 转义麻烦。生产代码推荐 java.nio.file.PathsFiles(NIO.2),本文以 IO 基础为主。

两大体系的核心区别

字符流(Reader/Writer):处理文本最顺手

1)字符输入:Reader 家族

修正与提升后的综合示例(包含三种读取方式,改为 try-with-resources、指定编码、健壮性更好):

import java.io.*;
import java.nio.charset.StandardCharsets;
public class ReaderDemo {
    public static void main(String[] args) {
        String path = "D:/IdeaProjects/JavaTest/src/com/qcby/a.txt";
        // 1) FileReader:简单,但依赖平台默认编码(不推荐在生产使用)
        try (FileReader reader = new FileReader(path)) {
            int ch;
            while ((ch = reader.read()) != -1) {
                System.out.print((char) ch);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 2) InputStreamReader:可指定编码(推荐)
        try (InputStreamReader reader = new InputStreamReader(
                new FileInputStream(path), StandardCharsets.UTF_8)) {
            int ch;
            while ((ch = reader.read()) != -1) {
                System.out.print((char) ch);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 3) BufferedReader:高效且支持按行读取
        try (BufferedReader br = new BufferedReader(new FileReader(path))) {
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

说明:FileReaderFileWriter 在编码未知或跨平台时不够稳妥,实际开发更推荐 InputStreamReader/OutputStreamWriter 并显式指定编码。

2)字符输出:Writer 家族

综合示例(修正:使用 try-with-resources,必要时 flush/close,路径与编码更明确):

import java.io.*;
import java.nio.charset.StandardCharsets;
public class WriterDemo {
    public static void main(String[] args) {
        String outPath = "D:/IO/output.txt";
        // 1) FileWriter:简单写文本
        try (FileWriter writer = new FileWriter(outPath)) { // 默认编码
            writer.write("Hello, World!\n");
            writer.write("This is a new line.\n");
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 2) OutputStreamWriter:指定编码(推荐)
        try (OutputStreamWriter writer = new OutputStreamWriter(
                new FileOutputStream(outPath, true), StandardCharsets.UTF_8)) { // 追加写
            writer.write("追加一行,使用UTF-8编码。\n");
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 3) BufferedWriter:高效按行写
        try (BufferedWriter bw = new BufferedWriter(new FileWriter(outPath, true))) {
            bw.write("Hello, World!");
            bw.newLine();
            bw.write("This is a new line.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3)Writer 的五种write方法(快速对照)

示例(修正笔记,补全导入与路径):

import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class WriterExample {
    public static void main(String[] args) {
        String out = "D:/IO/writer-demo.txt";
        try (Writer writer = new FileWriter(out)) {
            // 1. 写入单个字符
            writer.write('H');
            // 2. 写入字符数组
            char[] array = {'e', 'l', 'l', 'o'};
            writer.write(array);
            // 3. 写入字符数组的一部分(写入 "ll")
            writer.write(array, 2, 2);
            // 4. 写入字符串
            writer.write(", World!");
            // 5. 写入字符串的一部分(写入 "This is Java")
            String str = "\nThis is Java IO.";
            writer.write(str, 1, 12);
            System.out.println("数据已写入文件!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

字节流(InputStream/OutputStream):万能读写器

1)字节输入:InputStream 家族

基于笔记修正后的示例:

import java.io.*;
import java.nio.charset.StandardCharsets;
public class FileInputStreamTest {
    public static void main(String[] args) {
        File file = new File("D:/IO/hello.txt");
        // 建议:优先使用 try-with-resources,避免手动 finally 关闭
        try (FileInputStream fis = new FileInputStream(file)) {
            byte[] buffer = new byte[1024];
            int len;
            while ((len = fis.read(buffer)) != -1) {
                // 如果是文本,可按编码构造字符串;若是二进制,直接处理字节
                String chunk = new String(buffer, 0, len, StandardCharsets.UTF_8);
                System.out.print(chunk);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

注意:如果文件不是 UTF-8 文本,上面把字节解码为字符串可能出现乱码。处理图片/音频/视频等二进制文件时,不要把字节强行转成字符串。

2)字节输出:OutputStream 家族

增强示例(追加写入、换行、片段写入):

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class FileOutputStreamTest {
    public static void main(String[] args) {
        File file = new File("D:/IO/hello.txt");
        // true 表示追加写
        try (FileOutputStream fos = new FileOutputStream(file, true)) {
            fos.write(97); // 写入单字节 'a'
            fos.write("\r\n".getBytes(StandardCharsets.UTF_8));
            fos.write("中国人!\r\n".getBytes(StandardCharsets.UTF_8));
            fos.write("ABCDEFGH".getBytes(StandardCharsets.UTF_8), 2, 4); // 输出 CDEF
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Windows 的换行是 \r\n,Linux/Unix 是 \n。跨平台建议使用 System.lineSeparator()BufferedWriter.newLine()

性能与最佳实践

示例:拷贝任意文件(字节流 + 缓冲 + 大块读写)

import java.io.*;
public class FileCopy {
    public static void copyFile(String src, String dest) throws IOException {
        try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(src));
             BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest))) {
            byte[] buf = new byte[8192];
            int len;
            while ((len = in.read(buf)) != -1) {
                out.write(buf, 0, len);
            }
        }
    }
    public static void main(String[] args) throws IOException {
        copyFile("D:/IO/source.bin", "D:/IO/target.bin");
    }
}

字符编码与常见坑

什么时候用字节流?什么时候用字符流?

 实战:综合示例(读取一个 UTF-8 文本,转换后写入新文件)

import java.io.*;
import java.nio.charset.StandardCharsets;
public class TextTransformDemo {
    public static void main(String[] args) {
        String src = "D:/IO/input-utf8.txt";
        String dest = "D:/IO/output-utf8.txt";
        try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(src), StandardCharsets.UTF_8));
             BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(dest), StandardCharsets.UTF_8))) {
            String line;
            int lineNo = 1;
            while ((line = br.readLine()) != null) {
                // 简单转换:在每行前加上行号
                bw.write(String.format("%04d: %s", lineNo++, line));
                bw.newLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 进阶一瞥:NIO 与 Files(了解即可)

常见错误与改正

面试常见问题与答案

1)为什么有了字节流还需要字符流?

2)FileReaderInputStreamReader 区别?

3)BufferedReader.readLine() 为什么常用?

4)hashCode/equals 和 IO 有关系吗?

5)如何高效复制大文件?

6)什么时候需要 flush()

7)为什么 Windows 下是 \r\n 换行?

8)读取二进制文件时出现乱码怎么办?

9)FileFiles 的区别?

10)try-with-resources 的底层原理?

小结

到此这篇关于Java文件与IO流详细攻略的文章就介绍到这了,更多相关Java文件与IO流内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文