何为Java流
Java 中的流(Stream) 是用于在程序中读取或写入数据的抽象概念。流可以从不同的数据源(输入流)读取数据,也可以将数据写入到不同的目标(输出流)。流提供了一种统一的方式来处理不同类型的数据,例如文件、网络数据、内存数据等。
Java IO 流
在 Java 中,流分为输入流(InputStream) 和 输出流(OutputStream) 。输入流用于从数据源读取数据 ,而输出流用于将数据写入到目标。
IO 即 Input/Output,输入和输出。数据输入到计算机内存的过程即输入,反之输出到外部存储(比如数据库,文件,远程主机)的过程即输出。数据传输过程类似于水流,因此称为 IO 流。IO 流在 Java 中分为输入流和输出流,而根据数据的处理方式又分为字节流和字符流。
如果音频文件、图片等媒体文件用字节流比较好,如果涉及到字符的话使用字符流比较好。
Java IO 流的 40 多个类都是从如下 4 个抽象类基类中派生出来的。
-
InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流 -
OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流
java
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.IOException;
public class InputStreamReaderExample {
public static void main(String[] args) {
// 假设有一个字节流 InputStream
InputStream inputStream = getClass().getResourceAsStream("/example.txt");
try (InputStreamReader isr = new InputStreamReader(inputStream);
BufferedReader br = new BufferedReader(isr)) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
字符操作
Java提供了两个抽象类 来表示字符流输入输出:Reader 和 Writer 。
如果我们不知道编码类型就很容易出现乱码问题,因此I/O流提供了一个直接操作字符的接口,方便平时对字符进行流操作。

字符流
字符流 (Character Stream)以字符为单位进行读取和写入操作 ,适用于处理文本文件、配置文件、文档等纯文本数据。字符流是由 Java 虚拟机将字节转换得到的,默认采用的是 Unicode 编码,我们可以通过构造方法自定义编码。
字符流 = 字节流 + 编码表
乱码问题
在字节流中,一个字符通常由多个字节组成,而不同的字符编码使用的字节数不同。如果使用了错误的字符编码,或者在读取和写入数据时没有正确处理字符编码的转换,就会导致读取出来的中文字符出现乱码。

由于 String 的构造方法具有解码功能,使用这种方式也可以正确读出中文
使用 new String(byte bytes[], int offset, int length) 将字节流转换为字符串时,Java 会根据 UTF-8 的规则将每 3 个字节解码为一个中文字符,从而正确地解码出中文。
尽管字节流也有办法解决乱码问题,但不够直接,于是就有了字符流
Read 字符输入流
Reader 用于从源头(通常是文件)读取数据(字符信息)到内存中,java.io.Reader 抽象类是所有字符输入流的父类,提供读取字符流的共同方法和特性。
Reader 用于读取文本, InputStream 用于读取原始字节。
常用方法
-
read(): 从输入流读取一个字符,返回读取的字符(转为 int 类型),当读取到文件末尾时,返回-1。 -
read(char[] cbuf): 从输入流中读取一些字符,并将它们存储到字符数组cbuf中,等价于read(cbuf, 0, cbuf.length)。 -
read(char[] cbuf, int off, int len):在read(char[] cbuf)方法的基础上增加了off参数(偏移量)和len参数(要读取的最大字符数)。 -
skip(long n):忽略输入流中的 n 个字符 ,返回实际忽略的字符数。 -
close(): 关闭输入流并释放相关的系统资源。
常用子类
InputStreamReader
InputStreamReader 是字节流转换为字符流的桥梁,可以通过指定字符集来处理不同的编码方式。
java
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.IOException;
public class InputStreamReaderExample {
public static void main(String[] args) {
// 假设有一个字节流 InputStream
InputStream inputStream = getClass().getResourceAsStream("/example.txt");
try (InputStreamReader isr = new InputStreamReader(inputStream);
BufferedReader br = new BufferedReader(isr)) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
示例说明:
-
创建
InputStream:这里使用getClass().getResourceAsStream()方法来获取资源文件example.txt的InputStream。 -
创建
InputStreamReader:使用inputStream创建一个InputStreamReader,默认使用系统默认的字符集。 -
创建
BufferedReader:使用InputStreamReader创建一个BufferedReader,以便逐行读取数据。 -
读取数据 :通过
BufferedReader的readLine()方法逐行读取数据,并打印出来。
FileReader
FileReader 直接从文件中读取字符的输入流。继承自 InputStreamReader 类,因此它也可以处理字节流,并将其转换为字符流。
构造方法
FileReader(File file):创建一个新的FileReader,参数为File对象。FileReader(String fileName):创建一个新的FileReader,参数为文件名。
FileReader 实现了 AutoCloseable 接口,因此可以使用 try-with-source 语句自动关闭资源,避免了手动关闭资源的繁琐操作。
java
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;
public class FileReaderExample {
public static void main(String[] args) {
String filePath = "example.txt";
try (FileReader fr = new FileReader(filePath);
BufferedReader br = new BufferedReader(fr)) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
示例说明:
-
创建
FileReader:使用文件路径example.txt创建一个FileReader。 -
创建
BufferedReader:使用FileReader创建一个BufferedReader,以便逐行读取数据。 -
读取数据 :通过
BufferedReader的readLine()方法逐行读取数据,并打印出来。
BuffereredReader
BufferedReader 字符缓冲输入流,继承自 Reader 类。提供了缓冲功能,可以减少读取操作对底层资源文件的访问次数,提高读取效率。通常被用来逐行读取字符数据。
使用流程
-
创建字符输入流对象,选择合适的子类,例如
FileReader。 -
使用构造器来指定要读取的文件或其他字符源。
-
使用读取方法从流中读取字符数据,例如
read()或read(char[])。 -
处理读取的字符数据,可以将其保存到变量中,或者进行其他操作。
-
关闭字符输入流,释放资源,可以使用
close()方法(try-with-resources语句可自动释放资源)来关闭流。
java
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;
public class BufferedReaderExample {
public static void main(String[] args) {
String filePath = "example.txt";
try (FileReader fr = new FileReader(filePath);
BufferedReader br = new BufferedReader(fr)) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
示例说明:
-
创建
FileReader:使用文件路径example.txt创建一个FileReader。 -
创建
BufferedReader:使用FileReader创建一个BufferedReader,以便逐行读取数据。 -
读取数据 :通过
BufferedReader的readLine()方法逐行读取数据,并打印出来。
Write 字符输出流
Writer 用于将数据(字符信息)写入到目的地(通常是文件) ,java.io.Writer 抽象类是所有字符输出流的父类。提供了写入字符流的共同方法和特性。
常用方法
Writer 常用方法:
-
write(int c): 写入单个字符。 -
write(char[] cbuf):写入字符数组cbuf,等价于write(cbuf, 0, cbuf.length)。 -
write(char[] cbuf, int off, int len):在write(char[] cbuf)方法的基础上增加了off参数(偏移量)和len参数(要读取的最大字符数)。 -
write(String str):写入字符串,等价于write(str, 0, str.length())。 -
write(String str, int off, int len):在write(String str)方法的基础上增加了off参数(偏移量)和len参数(要读取的最大字符数)。 -
append(CharSequence csq):将指定的字符序列附加到指定的Writer对象并返回该Writer对象。 -
append(char c):将指定的字符附加到指定的Writer对象并返回该Writer对象。 -
flush():刷新此输出流并强制写出所有缓冲的输出字符。 -
close():关闭输出流释放相关的系统资源。
如果不关闭资源,数据只是保存到缓冲区,并未保存到文件中。
常用子类
FileWriter
FileWriter:用于向文件中写入字符数据 。通过指定文件路径和名称来创建一个用于写入文件的 FileWriter 对象,指定追加模式来续写或覆盖,类似于OutputStream。
FileWriter 内置了缓冲区 ByteBuffer,所以如果不关闭输出流,就无法把字符写入到文件中。

但是关闭了流对象,就无法继续写数据了。如果我们既想写入数据,又想继续使用流,就需要 flush 方法了。
flush:刷新缓冲区,流对象可以继续使用。
close:先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。
构造方法:
FileWriter 类提供了多个构造方法,用于创建不同类型的 FileWriter 对象。下面列出了 FileWriter 类最常用的构造方法及其用法:
FileWriter(String fileName):创建一个将数据写入指定文件的 FileWriter 对象。若指定文件不存在,则尝试创建该文件;若文件已存在,则会将其清空。
java
String fileName = "example.txt";
FileWriter fileWriter = new FileWriter(fileName);
FileWriter(String fileName, boolean append):创建一个将数据写入指定文件的 FileWriter 对象,append 参数用于控制是否在文件末尾追加数据。若 append 参数为 true,则在文件末尾追加数据;若 append 参数为 false,则会将文件清空。
java
String fileName = "example.txt";
boolean append = true;
FileWriter fileWriter = new FileWriter(fileName, append);
FileWriter(File file):创建一个将数据写入指定文件的 FileWriter 对象。若指定文件不存在,则尝试创建该文件;若文件已存在,则会将其清空。
java
File file = new File("example.txt");
FileWriter fileWriter = new FileWriter(file);
FileWriter(File file, boolean append):创建一个将数据写入指定文件的FileWriter对象,append 参数用于控制是否在文件末尾追加数据。若 append 参数为 true,则在文件末尾追加数据;若 append 参数为 false,则会将文件清空。
java
File file = new File("example.txt");
boolean append = true;
FileWriter fileWriter = new FileWriter(file, append);
-
fileName参数表示文件名或文件路径,file参数表示文件对象。 -
append参数默认为false,即默认在文件末尾覆盖数据。 -
在创建
FileWriter对象时,如果指定的文件或路径不存在,则会尝试创建相应的文件或目录。但是,如果没有创建权限或磁盘空间不足等原因,则会抛出IOException异常。 -
在写入完数据后,应该调用
close()方法关闭FileWriter对象,以释放相关资源。也可以使用try-with-resources语句自动关闭流
StringWriter
StringWriter:用于将字符数据写入一个字符串 。它包含了一个可变的字符串缓冲区,可以将写入的字符累积到缓冲区中,最终将缓冲区中的数据作为字符串返回。
缓冲区大小是根据需要动态增长的,因此没有固定的默认大小。向 StringWriter 写入字符时,如果缓冲区的空间不足,它会自动增加缓冲区的大小以适应更多的字符数据(无论是否指定大小)。
StringWriter 类的实现是线程安全的。
构造方法
StringWriter():创建一个初始化的空字符串缓冲区。
java
StringWriter stringWriter = new StringWriter();
StringWriter(int initialSize):创建一个指定初始大小的字符串缓冲区。
java
int initialSize = 1024;
StringWriter stringWriter = new StringWriter(initialSize);
-
在使用
StringWriter类时,不需要关心底层数据的存储位置,只需要通过write()方法写入数据即可。 -
写入完数据后,可以通过
toString()方法获取缓冲区中的数据字符串。如果需要清空字符串缓冲区,可以调用getBuffer().setLength(0)方法。
CharArrayWriter
CharArrayWriter 用于将字符数据写入一个字符数组 。它包含了一个可变的字符数组缓冲区,可以将写入的字符累积到缓冲区中,最终将缓冲区中的字符数组作为结果返回。
CharArrayWriter 的缓冲区大小是根据需要动态增长的,因此没有固定的默认大小。如果缓冲区的空间不足,它会自动增加缓冲区的大小以适应更多的字符数据。
CharArrayWriter 类的实现也是线程安全的。
构造方法
CharArrayWriter():创建一个初始化的空字符数组缓冲区。
java
CharArrayWriter charArrayWriter = new CharArrayWriter();
CharArrayWriter(int initialSize):创建一个指定初始大小的字符数组缓冲区。
java
int initialSize = 1024;
CharArrayWriter charArrayWriter = new CharArrayWriter(initialSize);
-
在使用
CharArrayWriter类时,不需要关心底层数据的存储位置,只需要通过write()方法写入数据即可。 -
写入完数据后,可以通过
toCharArray()方法获取缓冲区中的字符数组,并通过toString()方法将其转换为字符串。如果需要清空字符数组缓冲区,可以调用reset()方法。
BufferedWriter
BufferedWriter:用于向其他 Writer 对象提供缓冲功能,减少直接与底层目标进行 IO 操作的次数。它包装了其他 Writer 对象,提供了缓冲写入功能,可以一次写入大块数据,提高IO性能。
构造方法
BufferedWriter(Writer writer):创建一个使用默认缓冲区大小(8192 字节)的 BufferedWriter 对象。
java
BufferedWriter bufferedWriter = new BufferedWriter(writer);
BufferedWriter(Writer writer, int bufferSize):创建一个指定缓冲区大小的 BufferedWriter 对象。
java
int bufferSize = 4096;
BufferedWriter bufferedWriter = new BufferedWriter(writer, bufferSize);
BufferedWriter(Writer writer, int bufferSize, int maxBufferSize):创建一个指定缓冲区初始大小和最大容量的 BufferedWriter 对象。
java
int bufferSize = 1024;
int maxSize = 4096;
BufferedWriter bufferedWriter = new BufferedWriter(writer, bufferSize, maxSize);
-
BufferedWriter类是用来提高写入性能的,它会将数据先写入缓冲区,而不是直接写入目标流。当缓冲区满或发生显式调用flush()方法,缓冲区的内容将会真正写入到目标流中。 -
在使用完
BufferedWriter后,要记得调用close()方法关闭流,以释放资源,并确保缓冲区的内容被正确刷新到目标流中。
java
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.IOException;
public class BufferedWriterExample {
public static void main(String[] args) {
String filePath = "example.txt";
String content = "Hello, World!";
try (FileWriter fw = new FileWriter(filePath);
BufferedWriter bw = new BufferedWriter(fw)) {
bw.write(content);
} catch (IOException e) {
e.printStackTrace();
}
}
}
示例解释:
-
创建
FileWriter:使用文件路径example.txt创建一个FileWriter -
创建
BufferedWriter:使用FileWriter创建一个BufferedWriter,以便高效地写入数据 -
写入数据 :通过
BufferedWriter的write()方法写入字符串content
PrintWriter
PrintWriter:用于向文本输出流或字符输出流打印格式化的字符数据。它提供了一系列便利的 print() 和 println() 方法,可以轻松地将各种类型的数据输出为字符串。
构造方法
PrintWriter(OutputStream out):创建一个将文本输出到指定的 OutputStream 的 PrintWriter 对象。
java
OutputStream outputStream = new FileOutputStream("output.txt");
PrintWriter printWriter = new PrintWriter(outputStream);
PrintWriter(OutputStream out, boolean autoFlush):创建一个将文本输出到指定的 OutputStream 的 PrintWriter 对象,并指定是否自动刷新输出流。若 autoFlush 参数为 true,则在每次调用写入操作(如 print() 或 println())后会自动刷新输出流。
java
OutputStream outputStream = new FileOutputStream("output.txt");
boolean autoFlush = true;
PrintWriter printWriter = new PrintWriter(outputStream, autoFlush);
PrintWriter(Writer out):创建一个将文本输出到指定的 Writer 的 PrintWriter 对象。
java
Writer writer = new FileWriter("output.txt");
PrintWriter printWriter = new PrintWriter(writer);
PrintWriter(Writer out, boolean autoFlush):创建一个将文本输出到指定的 Writer 的 PrintWriter 对象,并指定是否自动刷新输出流。
java
Writer writer = new FileWriter("output.txt");
boolean autoFlush = true;
PrintWriter printWriter = new PrintWriter(writer, autoFlush);
字符缓冲流
字符缓冲流的基本方法与字符流调用方式一致。字符缓冲流有特有的方法。
-
BufferedReader:String readLine(): 读一行数据,读取到最后返回 null -
BufferedWriter:newLine(): 换行,由系统定义换行符。
BufferedReader 类和 BufferedWriter 类是Java IO库中提供的两个高效的字符流类,类似于字节缓冲流,用于在读取和写入字符时提供缓冲区功能。
BufferedReader 字符缓冲输入流
BufferedReader 类是 Reader 类的子类,它包装了一个现有的 Reader 对象,并提供了缓冲功能,可以一次读取一行字符数据。
BufferedReader 类提供了:
-
read()方法 用于读取单个字符 -
readLine()方法用于读取一行字符数据 -
mark()和reset()方法来支持标记和复位操作。
使用 BufferedReader 可以减少底层的IO操作次数,从而提高读取字符数据的效率。特别是在读取大型文本文件时,使用 BufferedReader 可以显著提升性能。
BufferedWriter 字符缓冲输出流
BufferedWriter 类是 Writer 类的子类,它包装了一个现有的 Writer 对象,并提供了缓冲功能,可以批量写入字符数据。
BufferedWriter 类提供了:
-
write()方法用于写入字符数据 -
newLine()方法用于写入换行符 -
flush()方法用于刷新缓冲区的数据。
使用 BufferedWriter 可以减少底层的IO操作次数,从而提高写入字符数据的效率。