news 2026/3/21 23:23:36

Java IO 基础理论知识笔记

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java IO 基础理论知识笔记

一、Java IO 概述

Java IO(Input/Output,输入 / 输出)是 Java 语言用于实现程序与外部设备(如文件、网络、控制台等)之间数据传输的核心技术。它是 Java 程序与外界交互的重要桥梁,比如读取本地配置文件、向磁盘写入日志、通过网络发送数据等场景,都离不开 Java IO 的支持。

Java IO 体系的设计基于流(Stream)的概念,流是一个抽象的概念,代表了数据的流动方向。根据数据的传输方向,可将流分为输入流和输出流:

  • 输入流(Input Stream):数据从外部设备流向程序,程序读取数据,例如读取文件中的内容到内存。
  • 输出流(Output Stream):数据从程序流向外部设备,程序写入数据,例如将内存中的数据写入到文件。

Java IO 体系主要包含两大核心部分:字节流字符流,此外还提供了缓冲流、转换流、对象流等功能扩展流,以满足不同的业务需求。

二、字节流(Byte Stream)

字节流是 Java IO 的基础,它以字节(Byte)为基本单位处理数据,一个字节占 8 位(bit)。字节流可以处理任意类型的文件,包括文本文件、图片、音频、视频等二进制文件,是 Java IO 中最通用的流类型。

字节流的顶层是两个抽象类:InputStream(字节输入流)和OutputStream(字节输出流),所有的字节输入流都继承自InputStream,所有的字节输出流都继承自OutputStream

1. 字节输入流(InputStream)核心方法

InputStream是所有字节输入流的父类,定义了字节输入流的通用操作,核心方法如下:

  • int read():从输入流中读取一个字节的数据,返回读取的字节值(0-255);如果到达流的末尾,返回-1
  • int read(byte[] b):从输入流中读取一定长度的字节,存储到字节数组b中,返回实际读取的字节数;如果到达流的末尾,返回-1
  • int read(byte[] b, int off, int len):从输入流中读取长度为len的字节,从字节数组b的下标off开始存储,返回实际读取的字节数。
  • void close():关闭输入流,释放相关的系统资源。注意:流使用完毕后必须关闭,否则会造成资源泄漏。

2. 字节输出流(OutputStream)核心方法

OutputStream是所有字节输出流的父类,核心方法如下:

  • void write(int b):将一个字节的数据写入输出流(注意:参数是 int 类型,但实际只写入低 8 位)。
  • void write(byte[] b):将字节数组b中的所有字节写入输出流。
  • void write(byte[] b, int off, int len):将字节数组b中从下标off开始、长度为len的字节写入输出流。
  • void flush():刷新输出流,将缓冲区中的数据强制写入目标设备。对于带缓冲区的输出流,此方法尤为重要。
  • void close():关闭输出流,释放系统资源。关闭前会自动调用flush()方法。

3. 常用字节流实现类

(1)文件字节流:FileInputStream & FileOutputStream

这是最常用的字节流实现类,用于操作本地文件,直接与文件系统交互。

  • FileInputStream:从本地文件中读取字节数据。构造方法:
// 通过文件路径创建流 FileInputStream fis = new FileInputStream("test.txt"); // 通过 File 对象创建流 File file = new File("test.txt"); FileInputStream fis = new FileInputStream(file);

FileOutputStream:向本地文件中写入字节数据。注意:如果文件不存在,会自动创建;如果文件已存在,默认会覆盖原有内容,也可以通过构造方法指定追加模式。构造方法:

// 覆盖模式 FileOutputStream fos = new FileOutputStream("test.txt"); // 追加模式 FileOutputStream fos = new FileOutputStream("test.txt", true);

使用示例:文件复制

import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class FileCopyDemo { public static void main(String[] args) { FileInputStream fis = null; FileOutputStream fos = null; try { // 1. 创建输入流和输出流 fis = new FileInputStream("source.jpg"); fos = new FileOutputStream("target.jpg"); // 2. 定义缓冲区,提高读写效率 byte[] buffer = new byte[1024]; int len; // 3. 循环读取并写入 while ((len = fis.read(buffer)) != -1) { fos.write(buffer, 0, len); } System.out.println("文件复制成功"); } catch (IOException e) { e.printStackTrace(); } finally { // 4. 关闭流,先关输出流,再关输入流 try { if (fos != null) fos.close(); if (fis != null) fis.close(); } catch (IOException e) { e.printStackTrace(); } } } }
(2)字节数组流:ByteArrayInputStream & ByteArrayOutputStream

字节数组流以内存中的字节数组为操作对象,数据的读取和写入都在内存中完成,不会涉及磁盘 IO,常用于临时数据的处理。

  • ByteArrayInputStream:从字节数组中读取数据。
  • ByteArrayOutputStream:向内存中的字节数组写入数据,其内部会自动扩容,可通过toByteArray()方法获取写入的字节数组。
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; public class ByteArrayStreamDemo { public static void main(String[] args) throws IOException { String content = "Hello, Java IO!"; byte[] bytes = content.getBytes(); // 字节数组输入流 ByteArrayInputStream bais = new ByteArrayInputStream(bytes); // 字节数组输出流 ByteArrayOutputStream baos = new ByteArrayOutputStream(); int len; byte[] buffer = new byte[10]; while ((len = bais.read(buffer)) != -1) { baos.write(buffer, 0, len); } // 获取写入的字节数组并转换为字符串 String result = baos.toString(); System.out.println(result); // 输出:Hello, Java IO! // 关闭流(字节数组流关闭后不影响内存数据,可省略,但建议养成习惯) bais.close(); baos.close(); } }

三、字符流(Character Stream)

字节流以字节为单位处理数据,在处理文本文件时,需要考虑字符编码(如 UTF-8、GBK),否则容易出现乱码问题。字符流正是为了解决这一问题而设计的,它以字符(Character)为基本单位处理数据,一个字符通常占 2 个字节(Java 中 char 类型是 16 位),并且会自动处理字符编码问题。

字符流的顶层是两个抽象类:Reader(字符输入流)和Writer(字符输出流),所有字符输入流都继承自Reader,所有字符输出流都继承自Writer

1. 字符输入流(Reader)核心方法

  • int read():读取一个字符,返回字符的 Unicode 编码值;如果到达流的末尾,返回-1
  • int read(char[] cbuf):读取若干字符到字符数组cbuf中,返回实际读取的字符数;末尾返回-1
  • int read(char[] cbuf, int off, int len):读取长度为len的字符,从字符数组cbuf的下标off开始存储。
  • void close():关闭字符输入流,释放资源。

2. 字符输出流(Writer)核心方法

  • void write(int c):写入一个字符(参数是 int 类型,实际写入低 16 位)。
  • void write(char[] cbuf):写入字符数组cbuf中的所有字符。
  • void write(char[] cbuf, int off, int len):写入字符数组cbuf中从off开始、长度为len的字符。
  • void write(String str):直接写入一个字符串,这是字符流特有的便捷方法。
  • void write(String str, int off, int len):写入字符串str中从off开始、长度为len的子串。
  • void flush():刷新缓冲区,将数据写入目标设备。
  • void close():关闭输出流,关闭前自动刷新。

3. 常用字符流实现类

(1)文件字符流:FileReader & FileWriter

用于操作本地文本文件,底层会默认使用系统的字符编码,也可以通过指定编码来避免乱码(JDK 11 及以上支持通过构造方法指定编码)。

  • FileReader:读取文本文件内容。构造方法:
FileReader fr = new FileReader("test.txt"); // 指定编码(JDK 11+) FileReader fr = new FileReader("test.txt", Charset.forName("UTF-8"));

FileWriter:向文本文件写入内容,支持覆盖和追加模式。构造方法:

// 覆盖模式 FileWriter fw = new FileWriter("test.txt"); // 追加模式 FileWriter fw = new FileWriter("test.txt", true); // 指定编码(JDK 11+) FileWriter fw = new FileWriter("test.txt", Charset.forName("UTF-8"), true);

使用示例:文本文件读写

import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class FileReaderWriterDemo { public static void main(String[] args) { FileReader fr = null; FileWriter fw = null; try { // 1. 创建输入流(读取文件)和输出流(写入文件,追加模式) fr = new FileReader("source.txt"); fw = new FileWriter("target.txt", true); // 2. 定义字符缓冲区 char[] cbuf = new char[1024]; int len; // 3. 循环读取并写入 while ((len = fr.read(cbuf)) != -1) { fw.write(cbuf, 0, len); } System.out.println("文本写入成功"); } catch (IOException e) { e.printStackTrace(); } finally { // 4. 关闭流 try { if (fw != null) fw.close(); if (fr != null) fr.close(); } catch (IOException e) { e.printStackTrace(); } } } }
(2)缓冲字符流:BufferedReader & BufferedWriter

缓冲字符流是对普通字符流的包装,它在内存中开辟了一个缓冲区,读写数据时先操作缓冲区,减少了与磁盘的交互次数,从而大幅提高读写效率。同时,BufferedReader提供了readLine()方法,可以一次性读取一行文本,非常适合处理按行存储的文本文件。

  • BufferedReader:包装字符输入流,提供缓冲功能和按行读取方法。构造方法:

    java

    运行

    // 包装 FileReader BufferedReader br = new BufferedReader(new FileReader("test.txt"));
    特有方法:String readLine():读取一行文本,返回包含该行内容的字符串;如果到达流的末尾,返回null
  • BufferedWriter:包装字符输出流,提供缓冲功能和换行方法。构造方法:

    java

    运行

    BufferedWriter bw = new BufferedWriter(new FileWriter("test.txt"));
    特有方法:void newLine():写入一个换行符,适配不同操作系统的换行规则(Windows 是\r\n,Linux 是\n)。

使用示例:按行读取文本文件

import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class BufferedReaderDemo { public static void main(String[] args) { BufferedReader br = null; try { br = new BufferedReader(new FileReader("test.txt")); String line; // 按行读取文本,直到末尾 while ((line = br.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (br != null) br.close(); } catch (IOException e) { e.printStackTrace(); } } } }

四、转换流:InputStreamReader & OutputStreamWriter

转换流是字节流和字符流之间的桥梁,它可以将字节流转换为字符流,并在转换过程中指定字符编码,从而解决字符流的编码问题。

  • InputStreamReader:将字节输入流(InputStream)转换为字符输入流(Reader)。
  • OutputStreamWriter:将字节输出流(OutputStream)转换为字符输出流(Writer)。

构造方法中需要传入字节流对象和指定的字符编码:

java

运行

// 将 FileInputStream 转换为字符输入流,指定 UTF-8 编码 InputStreamReader isr = new InputStreamReader(new FileInputStream("test.txt"), "UTF-8"); // 将 FileOutputStream 转换为字符输出流,指定 GBK 编码 OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("test.txt"), "GBK");

使用场景:当需要读取或写入文本文件,且需要明确指定字符编码时,使用转换流可以避免乱码。例如,读取一个 GBK 编码的文本文件:

import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; public class InputStreamReaderDemo { public static void main(String[] args) { InputStreamReader isr = null; try { // 指定 GBK 编码读取文件 isr = new InputStreamReader(new FileInputStream("gbk.txt"), "GBK"); char[] cbuf = new char[1024]; int len; while ((len = isr.read(cbuf)) != -1) { System.out.println(new String(cbuf, 0, len)); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (isr != null) isr.close(); } catch (IOException e) { e.printStackTrace(); } } } }

五、缓冲流(Buffered Stream)

缓冲流是对字节流和字符流的增强,它的核心作用是通过缓冲区减少磁盘 IO 次数,提高读写性能。缓冲流分为字节缓冲流字符缓冲流

  • 字节缓冲流BufferedInputStream(包装字节输入流)、BufferedOutputStream(包装字节输出流)。
  • 字符缓冲流BufferedReaderBufferedWriter(前文已介绍)。

缓冲流的使用规则是包装流:创建缓冲流对象时,传入一个普通的字节流或字符流对象,底层的读写操作由缓冲流优化。

字节缓冲流使用示例:

import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class BufferedStreamDemo { public static void main(String[] args) { BufferedInputStream bis = null; BufferedOutputStream bos = null; try { // 包装 FileInputStream 和 FileOutputStream bis = new BufferedInputStream(new FileInputStream("source.mp4")); bos = new BufferedOutputStream(new FileOutputStream("target.mp4")); byte[] buffer = new byte[1024]; int len; while ((len = bis.read(buffer)) != -1) { bos.write(buffer, 0, len); } System.out.println("视频文件复制成功"); } catch (IOException e) { e.printStackTrace(); } finally { try { if (bos != null) bos.close(); if (bis != null) bis.close(); } catch (IOException e) { e.printStackTrace(); } } } }

六、对象流:ObjectInputStream & ObjectOutputStream

对象流用于实现对象的序列化和反序列化。序列化是指将内存中的 Java 对象转换为字节序列,以便存储到文件或通过网络传输;反序列化则是将字节序列恢复为 Java 对象。

要实现序列化,对象所属的类必须实现Serializable接口(这是一个标记接口,没有任何方法),否则会抛出NotSerializableException异常。

1. 核心方法

  • ObjectOutputStream(序列化):void writeObject(Object obj):将对象写入输出流。
  • ObjectInputStream(反序列化):Object readObject():从输入流中读取对象,返回值需要强制类型转换。

2. 使用示例

步骤 1:定义可序列化的类

import java.io.Serializable; // 实现 Serializable 接口 public class Student implements Serializable { // 序列化版本号,用于保证序列化和反序列化的类版本一致 private static final long serialVersionUID = 1L; private String name; private int age; public Student(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Student{name='" + name + "', age=" + age + "}"; } }

步骤 2:对象的序列化和反序列化

import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class ObjectStreamDemo { public static void main(String[] args) throws Exception { // 1. 序列化:将 Student 对象写入文件 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("student.txt")); oos.writeObject(new Student("张三", 20)); oos.close(); // 2. 反序列化:从文件中读取 Student 对象 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("student.txt")); Student student = (Student) ois.readObject(); System.out.println(student); // 输出:Student{name='张三', age=20} ois.close(); } }

七、Java IO 核心注意事项

八、字节流与字符流的区别

对比维度字节流字符流
数据单位字节(8 位)字符(16 位)
处理对象所有文件(文本、图片、视频等)仅文本文件
编码处理不处理编码,可能出现乱码自动处理编码,避免乱码
顶层抽象类InputStreamOutputStreamReaderWriter
特有方法readLine()write(String)newLine()
  1. 资源关闭:流使用完毕后必须调用close()方法关闭,否则会造成系统资源泄漏。在 JDK 7 及以上,可以使用try-with-resources语法,自动关闭实现了AutoCloseable接口的资源,简化代码:
    try (FileInputStream fis = new FileInputStream("test.txt"); FileOutputStream fos = new FileOutputStream("test_copy.txt")) { byte[] buffer = new byte[1024]; int len; while ((len = fis.read(buffer)) != -1) { fos.write(buffer, 0, len); } } catch (IOException e) { e.printStackTrace(); }
  2. 编码问题:处理文本文件时,优先使用字符流或转换流,并明确指定字符编码(如 UTF-8),避免因系统默认编码不同导致乱码。
  3. 缓冲区刷新:带缓冲区的输出流(如BufferedOutputStreamBufferedWriter),在数据写入后需要调用flush()方法,确保缓冲区中的数据全部写入目标设备。
  4. 序列化注意事项
    • 类的serialVersionUID建议显式声明,避免类结构变化后反序列化失败。
    • transient修饰的成员变量不会被序列化。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/13 12:13:26

数学思维之数学归纳法

我们在现实中,归纳是一种很重要的学习技术,但是归纳受制于样本空间,你不可能无限采样进行推理,这导致归纳被很多民科视为伪科学,在历史上归纳法曾经被认为是伪科学。 在数学中,为了避免无限采样问题&#…

作者头像 李华
网站建设 2026/3/15 4:25:51

为什么顶尖团队都在抢读Open-AutoGLM文档?真相令人震惊

第一章:Open-AutoGLM的诞生与行业影响 Open-AutoGLM 是近年来开源大语言模型领域的一项重要突破,其诞生标志着自动化生成语言模型从实验研究走向工业级应用。该项目由全球多个顶尖研究机构联合发起,旨在构建一个完全开放、可复现、支持多任务…

作者头像 李华
网站建设 2026/3/14 16:50:31

结合Diffusers生成图像解释复杂概念

结合Diffusers生成图像解释复杂概念 在信息爆炸的时代,企业与个人每天都在产生海量文档——从产品手册到内部培训资料,从客户合同到技术白皮书。然而,这些知识往往沉睡在PDF或硬盘角落里,难以被高效利用。传统的搜索引擎依赖关键…

作者头像 李华
网站建设 2026/3/21 2:04:15

家具购物商城|基于java+ vue家具购物商城系统(源码+数据库+文档)

家具购物商城 目录 基于springboot vue家具购物商城系统 一、前言 二、系统功能演示 三、技术选型 四、其他项目参考 五、代码参考 六、测试参考 七、最新计算机毕设选题推荐 八、源码获取: 基于springboot vue家具购物商城系统 一、前言 博主介绍&…

作者头像 李华
网站建设 2026/3/17 23:02:12

宝塔线彩带主图买卖点 趋势 操盘控盘 无未来函数

{} DRAWGBK(O>0,RGB(33,47,58),RGB(0,0,0),0,02,0);{渐变色灰下黑背景} MA5:MA(CLOSE,5),COLORWHITE; MA10:MA(CLOSE,10),COLORYELLOW; MA20:MA(CLOSE,20),POINTDOT,COLORMAGENTA; MA30:MA(CLOSE,30),COLORRED; MA60:MA(CLOSE,60),COLORGREEN LINETHICK1; MA120:MA(CLOSE,1…

作者头像 李华