JAVA中的IO操作

一、IO基础

1、什么是IO

IO,即 Input/Output,翻译过来就是输入输出 。在 Java 编程中,它是程序与外部世界进行数据交互的关键方式。简单来说,输入就是程序从外部获取数据,比如从文件中读取内容、接收网络传来的数据;输出则是程序将数据发送到外部,像将数据写入文件、向网络另一端发送数据。

打个比方,我们日常使用的手机,当我们从相册中打开一张照片时,照片的数据从手机存储设备进入到手机应用程序,这就类似于 Java 程序中的输入操作;而当我们拍摄一张新照片并保存到相册时,照片的数据从手机相机应用程序保存到手机存储设备,这就类似于 Java 程序中的输出操作。在 Java 世界里,IO 操作让程序能够与文件系统、网络、控制台等外部环境进行数据的交换,从而实现各种各样的功能。

2、JavaIO本质是在解决什么问题

Java IO 本质就干三件事:
读文件
写文件
网络数据传输(HTTP / Socket)

二、IO核心概念

1、流的概念

在 Java IO 中,流(Stream)是一个非常重要的概念。可以把流想象成一条数据传输的通道,数据就像水流一样在这个通道中流动。它具有方向性,数据从数据源流向程序(输入流),或者从程序流向数据目的地(输出流)。并且,流中的数据是按顺序依次传输的,就像水流是依次流淌一样 。数据在流中是以字节(byte)或者字符(char)为单位进行传输的。例如,当从一个文本文件中读取数据时,数据会以字节或者字符的形式通过输入流进入程序;当向文件写入数据时,数据会以字节或字符的形式通过输出流从程序流向文件。

2、输入流(InputStream)

用于从外部数据源读取数据到程序中。在 Java 中,所有输入流的基类是InputStream(字节输入流)和Reader(字符输入流) 。例如,当我们想要读取一个文本文件的内容时,可以使用FileInputStream(InputStream的子类)或者FileReader(Reader的子类)。

就是:把数据读进来

比如:读文件、读接口返回的数据、读图片、读前端上传的文件

3、输出流(OutputStream)

用于将程序中的数据写入到外部数据目的地。Java 中所有输出流的基类是OutputStream(字节输出流)和Writer(字符输出流) 。比如,要将一些文本内容写入文件,可以使用FileOutputStream(OutputStream的子类)或者FileWriter(Writer的子类)。以下是使用FileWriter写入文件的示例代码:

就是:把数据写出去

比如:写文件、把文件返回给前端、写日志文件、把图片保存到服务器

4、字节流

以字节(8 位)为单位处理数据,适用于处理任何类型的数据,包括二进制数据,如图片、音频、视频等 。InputStream和OutputStream是字节流的抽象基类,它们的子类如FileInputStream、FileOutputStream、ByteArrayInputStream、ByteArrayOutputStream等,广泛应用于各种字节数据的读写操作。例如,读取一张图片文件并输出其字节数据:

java 复制代码
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class ByteStreamExample {
    public static void main(String[] args) {
        try (InputStream inputStream = new FileInputStream("image.jpg")) {
            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) != -1) {
                for (int i = 0; i < length; i++) {
                    System.out.print(buffer[i] + " ");
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
5、字符流

以字符(16 位 Unicode)为单位处理数据,主要用于处理文本数据 。Reader和Writer是字符流的抽象基类,其常见子类有FileReader、FileWriter、BufferedReader、BufferedWriter等。字符流在处理文本时,会自动进行字符编码转换,方便处理不同编码格式的文本文件。比如,读取一个 UTF-8 编码的文本文件并输出内容:

复制代码
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

public class CharacterStreamExample {
    public static void main(String[] args) {
        try (Reader reader = new FileReader("text.txt");
             BufferedReader bufferedReader = new BufferedReader(reader)) {
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

字节流和字符流的主要区别在于处理数据的单位和应用场景。字节流更通用,可以处理任何类型的数据,但在处理文本时需要手动处理字符编码问题;字符流专门用于处理文本数据,自动处理字符编码,使用起来更方便,但不适用于二进制数据的处理。

6、 按功能分类

节点流:也称为低级流,是直接与数据源或数据目的地相连的流,负责从数据源读取数据或直接将数据写入数据目的地 。例如,FileInputStream和FileOutputStream直接操作文件,ByteArrayInputStream和ByteArrayOutputStream直接操作字节数组,它们都是节点流。以FileInputStream读取文件为例:

java 复制代码
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class NodeStreamExample {
    public static void main(String[] args) {
        try (InputStream inputStream = new FileInputStream("test.txt")) {
            int data;
            while ((data = inputStream.read()) != -1) {
                System.out.print((char) data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

处理流:也叫包装流,是在节点流的基础上进行包装,增强了流的功能,如提高读写效率、增加数据处理能力等 。处理流不能单独存在,必须连接在其他流(通常是节点流)之上。例如,BufferedInputStream和BufferedOutputStream通过缓冲机制提高了数据读写的效率,它们通常会包装FileInputStream和FileOutputStream。下面是使用BufferedInputStream包装FileInputStream来提高读取效率的示例:

java 复制代码
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class ProcessingStreamExample {
    public static void main(String[] args) {
        try (InputStream inputStream = new FileInputStream("test.txt");
             BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream)) {
            byte[] buffer = new byte[1024];
            int length;
            while ((length = bufferedInputStream.read(buffer)) != -1) {
                System.out.write(buffer, 0, length);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在这个例子中,BufferedInputStream在FileInputStream的基础上增加了缓冲区,减少了系统 I/O 操作的次数,从而提高了读取效率。处理流的存在使得 Java IO 的操作更加灵活和高效,开发者可以根据具体需求选择合适的处理流来包装节点流,实现各种复杂的数据处理功能。

三、Java IO 中常用的类

1、最基础的四个父类

这四个你要先认识,它们是所有 IO 类的"根"。

1. InputStream
作用:
按字节读取数据
适合: 图片、视频、pdf、压缩包、任意二进制数据
例子:

java 复制代码
InputStream in = new FileInputStream("a.jpg");
int b = in.read();
in.close();

理解:read() 每次读取一个字节。

2. OutputStream
作用:
按字节写出数据

例子:

java 复制代码
OutputStream out = new FileOutputStream("b.jpg");
out.write(97);
out.close();

这里 97 对应字节值,写出去后可能是字符 a

3. Reader
作用:
按字符读取数据
适合: txt、json、xml、配置文件
例子:

java 复制代码
Reader reader = new FileReader("a.txt");
int ch = reader.read();
reader.close();

4. Writer
作用:
按字符写出数据
例子:

java 复制代码
Writer writer = new FileWriter("a.txt");
writer.write("你好");
writer.close();
2、文件流:和文件直接打交道

这是最常见的一组。

1. FileInputStream
作用:
从文件中读取字节

**例子:**读取图片

java 复制代码
FileInputStream in = new FileInputStream("d:/test/a.jpg");
byte[] buf = new byte[1024];
int len;

while ((len = in.read(buf)) != -1) {
    System.out.println("本次读取字节数:" + len);
}

in.close();

**什么时候用:**读图片、读 pdf、读压缩包、读任意文件原始内容

2. FileOutputStream
作用:
向文件中写字节

**例子:**写文件

java 复制代码
FileOutputStream out = new FileOutputStream("d:/test/b.txt");
out.write("hello".getBytes());
out.close();

**什么时候用:**保存文件、下载文件到本地、写二进制内容

3. FileReader
作用:
从文件中读取字符

**例子:**读取文本

java 复制代码
FileReader reader = new FileReader("d:/test/a.txt");
char[] buf = new char[1024];
int len;

while ((len = reader.read(buf)) != -1) {
    System.out.print(new String(buf, 0, len));
}

reader.close();

什么时候用: 读普通文本文件、读日志文件、读配置文件
注意: FileReader 默认用系统编码,实际开发里更推荐 InputStreamReader 指定编码。

4. FileWriter
作用:
向文件中写字符

**例子:**写文本

java 复制代码
FileWriter writer = new FileWriter("d:/test/a.txt");
writer.write("第一行\n");
writer.write("第二行\n");
writer.close();

**什么时候用:**写文本文件、生成日志、输出字符串内容

3、缓冲流:提高性能

缓冲流的思想很简单:别一次只读一个字节、写一个字节,先放到内存缓冲区里,再统一处理。

1. BufferedInputStream
作用:
给字节输入流加缓冲

**例子:**读取图片

java 复制代码
BufferedInputStream bis = new BufferedInputStream(
    new FileInputStream("d:/test/a.jpg")
);

byte[] buf = new byte[1024];
int len;

while ((len = bis.read(buf)) != -1) {
    System.out.println("读取:" + len);
}

bis.close();

什么时候用:文件读操作几乎都可以加、网络输入也常加

2. BufferedOutputStream
作用:
给字节输出流加缓冲

**例子:**复制文件

java 复制代码
BufferedInputStream bis = new BufferedInputStream(
    new FileInputStream("d:/test/a.jpg")
);
BufferedOutputStream bos = new BufferedOutputStream(
    new FileOutputStream("d:/test/b.jpg")
);

byte[] buf = new byte[1024];
int len;

while ((len = bis.read(buf)) != -1) {
    bos.write(buf, 0, len);
}

bos.close();
bis.close();

什么时候用:文件复制、文件下载、大文件写出

3. BufferedReader
作用:
给字符输入流加缓冲、可以按行读取

**例子:**按行读文本

java 复制代码
BufferedInputStream bis = new BufferedInputStream(
    new FileInputStream("d:/test/a.jpg")
);
BufferedOutputStream bos = new BufferedOutputStream(
    new FileOutputStream("d:/test/b.jpg")
);

byte[] buf = new byte[1024];
int len;

while ((len = bis.read(buf)) != -1) {
    bos.write(buf, 0, len);
}

bos.close();
bis.close();

什么时候用: 读 txt、读日志、读配置文件、按行处理文本

这是文本处理里非常常用的类。

4. BufferedWriter
作用:
高效写文本

**例子:**写多行文本

java 复制代码
BufferedWriter bw = new BufferedWriter(
    new FileWriter("d:/test/a.txt")
);

bw.write("第一行");
bw.newLine();
bw.write("第二行");
bw.newLine();

bw.close();

**什么时候用:**写日志、写报表文本、写配置文件、输出多行字符串

4、转换流:处理编码问题

这两个类非常重要。

因为很多时候,底层拿到的是字节,但你要操作的是字符。

1. InputStreamReader
作用:
把字节输入流转换成字符输入流

**例子:**按 UTF-8 读取文本

java 复制代码
BufferedReader br = new BufferedReader(
    new InputStreamReader(
        new FileInputStream("d:/test/a.txt"),
        "UTF-8"
    )
);

String line;
while ((line = br.readLine()) != null) {
    System.out.println(line);
}

br.close();

什么时候用: 读取中文文本、处理乱码、读取网络响应文本、读取接口返回的 JSON
理解:

FileInputStream 负责从文件取字节。
InputStreamReader 负责把字节按 UTF-8 变成字符。
BufferedReader 负责按行读。

2. OutputStreamWriter
作用:
把字符写成指定编码的字节

**例子:**按 UTF-8 写文本

java 复制代码
BufferedWriter bw = new BufferedWriter(
    new OutputStreamWriter(
        new FileOutputStream("d:/test/a.txt"),
        "UTF-8"
    )
);

bw.write("你好,Java IO");
bw.newLine();
bw.write("第二行");

bw.close();

**什么时候用:**写中文文本、导出 txt/csv、往网络里写文本内容

5、内存流:数据不进文件,直接放内存里

这个很重要,很多接口开发里会遇到。

1. ByteArrayInputStream
作用:
从内存里的 byte[] 读取数据

例子:

java 复制代码
DataOutputStream dos = new DataOutputStream(
    new FileOutputStream("d:/test/data.bin")
);

dos.writeInt(100);
dos.writeDouble(3.14);
dos.writeBoolean(true);

dos.close();

**什么时候用:**测试代码、模拟输入流、已经有 byte[],但下游方法要求传 InputStream

2. ByteArrayOutputStream
作用:
往内存里写字节,最后拿到完整 byte[]
例子:

java 复制代码
DataInputStream dis = new DataInputStream(
    new FileInputStream("d:/test/data.bin")
);

int a = dis.readInt();
double b = dis.readDouble();
boolean c = dis.readBoolean();

System.out.println(a);
System.out.println(b);
System.out.println(c);

dis.close();

**什么时候用:**拼接数据、临时缓存、文件下载前先组装内容、接口返回前先把内容写进内存,这是非常常用的内存流。

3. StringReader
作用:
把字符串当成输入流来读
例子:

java 复制代码
StringReader sr = new StringReader("abc123");
int ch;

while ((ch = sr.read()) != -1) {
    System.out.print((char) ch);
}

sr.close();

**什么时候用:**已经有字符串,但希望按 Reader 的方式处理它

4. StringWriter
作用:
把字符写到内存中的字符串里
例子:

java 复制代码
StringWriter sw = new StringWriter();
sw.write("hello");
sw.write(" java");

String result = sw.toString();
System.out.println(result);

sw.close();

什么时候用: 在内存中拼接字符串、某些模板输出、替代 StringBuilder 的流式写法

6、数据流:按基本类型读写

1. DataOutputStream
作用:
按 Java 基本类型写数据
例子:

java 复制代码
DataOutputStream dos = new DataOutputStream(
    new FileOutputStream("d:/test/data.bin")
);

dos.writeInt(100);
dos.writeDouble(3.14);
dos.writeBoolean(true);

dos.close();

2. DataInputStream
作用:
按写入顺序读取基本类型

例子:

java 复制代码
DataInputStream dis = new DataInputStream(
    new FileInputStream("d:/test/data.bin")
);

int a = dis.readInt();
double b = dis.readDouble();
boolean c = dis.readBoolean();

System.out.println(a);
System.out.println(b);
System.out.println(c);

dis.close();

什么时候用: 需要严格按类型保存和读取数据、Java 内部二进制格式处理

**注意:**读取顺序必须和写入顺序一致。

7、对象流:直接读写 Java 对象

1. ObjectOutputStream
作用:
把对象写出去
例子:

java 复制代码
import java.io.Serializable;

class User implements Serializable {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
}


ObjectOutputStream oos = new ObjectOutputStream(
    new FileOutputStream("d:/test/user.obj")
);

User user = new User("张三", 20);
oos.writeObject(user);

oos.close();

2. ObjectInputStream
作用:
把对象读回来

例子:

java 复制代码
ObjectInputStream ois = new ObjectInputStream(
    new FileInputStream("d:/test/user.obj")
);

User user = (User) ois.readObject();

ois.close();

什么时候用: Java 对象持久化、Java 对象网络传输、学习序列化机制

注意: 类必须实现 Serializable

作用 常见例子
FileInputStream 读文件字节 读图片、pdf
FileOutputStream 写文件字节 保存文件
FileReader 读文件字符 读 txt
FileWriter 写文件字符 写 txt
BufferedInputStream 字节缓冲读 提高文件读取性能
BufferedOutputStream 字节缓冲写 高效复制文件
BufferedReader 字符缓冲读 按行读文本
BufferedWriter 字符缓冲写 高效写文本
InputStreamReader 字节转字符 解决乱码
OutputStreamWriter 字符转字节 指定编码输出
ByteArrayInputStream 从 byte[] 读 模拟输入
ByteArrayOutputStream 写到 byte[] 内存拼接数据
StringReader 从字符串读 把字符串当流处理
StringWriter 写到字符串 内存中拼文本
DataInputStream 读基本类型 readInt/readDouble
DataOutputStream 写基本类型 writeInt/writeDouble
ObjectInputStream 读对象 反序列化
ObjectOutputStream 写对象 序列化
PrintStream 方便输出 System.out
PrintWriter 方便写文本 println 输出文本

四、

相关推荐
Highcharts.js2 小时前
React 图表如何实现下钻(Drilldown)效果
开发语言·前端·javascript·react.js·前端框架·数据可视化·highcharts
s09071362 小时前
【声纳成像】基于滑动子孔径与加权拼接的条带式多子阵SAS连续成像(MATLAB仿真)
开发语言·算法·matlab·合成孔径声呐·后向投影算法·条带拼接
深蓝轨迹2 小时前
@Autowired与@Resource:Spring依赖注入注解核心差异剖析
java·python·spring·注解
不想看见4042 小时前
C++八股文【详细总结】
java·开发语言·c++
2401_891655812 小时前
此电脑网络位置异常的AD域排错指南的技术文章大纲
开发语言·python·算法
江公望2 小时前
C++11 std::function,10分钟讲清楚
开发语言·c++
leaves falling2 小时前
C++入门基础
开发语言·c++
huaweichenai2 小时前
java的数据类型介绍
java·开发语言
C羊驼3 小时前
C语言:随机数
c语言·开发语言·经验分享·笔记·算法