按功能来分为输入流和输出流;按类型来分为字节流和字符流。
Java中的流都是从下面四个抽象基类中派生出来的:
- InputStream/Reader:所有输入流的基类,前者是字节输入流,后者是字符输入流;
- OutputStream/Writer:所有输出流的基类前者是字节输出流,后者是字符输出流。
一 、字节流
以字节为单位进行数据传输(8位),适用于处理二进制数据或者未经字符编码的文本数据。
InputStream字节输入流
InputStream
是 Java 中用于处理字节输入流的抽象类。它是所有字节输入流类的父类,提供了一些基本的方法来读取字节数据。
以下是 InputStream
类的一些主要方法和说明:
-
int read()
:- 从输入流中读取下一个字节的数据,并返回读取的字节(0~255之间的整数值),如果已经到达输入流的末尾,则返回 -1。
- 如果读取的字节为负数,则表示字节数据的最高位为 1,需要转换为无符号整数才能正确表示字节的值。
-
int read(byte[] b)
:- 从输入流中读取多个字节的数据,并将其存储到字节数组
b
中。 - 返回实际读取的字节数,如果已经到达输入流的末尾,则返回 -1。
- 从输入流中读取多个字节的数据,并将其存储到字节数组
-
int read(byte[] b, int off, int len)
:- 从输入流中读取多个字节的数据,并将其存储到字节数组
b
中,从偏移量off
开始存储,最多读取len
个字节。 - 返回实际读取的字节数,如果已经到达输入流的末尾,则返回 -1。
- 从输入流中读取多个字节的数据,并将其存储到字节数组
-
long skip(long n)
:- 跳过输入流中的
n
个字节,返回实际跳过的字节数。 - 注意:该方法不保证一定成功跳过
n
个字节,可能会跳过比n
少的字节数。
- 跳过输入流中的
-
int available()
:- 返回可以从输入流中读取而不受阻塞的字节数。
- 注意:
available()
方法返回的字节数可能不准确,不应该用于检查是否已经读取完所有的数据。
-
void close()
:- 关闭输入流并释放与之相关的资源。
以下是一个简单的示例代码,演示如何使用
InputStream
来读取文件中的字节数据:import java.io.*; public class InputStreamExample { public static void main(String[] args) { try { // 创建一个 FileInputStream 对象来读取文件 InputStream inputStream = new FileInputStream("example.txt"); // 读取文件中的字节数据 int data; while ((data = inputStream.read()) != -1) { // 将读取的字节数据转换为字符并打印出来 System.out.print((char) data); } // 关闭输入流 inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } }
在这个示例中,我们使用
FileInputStream
来创建一个InputStream
对象,然后通过read()
方法逐个字节地读取文件中的数据,直到到达文件末尾(read()
方法返回 -1)。每次读取到一个字节后,我们将其转换为字符并打印出来。需要注意的是,在实际开发中,应该始终在使用完毕后关闭输入流,以释放相关资源。因此,我们在
finally
块中调用close()
方法来关闭输入流,以确保即使发生异常,输入流也能够被正确关闭。
InputStream
是一个抽象类,不能直接实例化,常用的实现类包括:
FileInputStream
:用于从文件中读取数据。ByteArrayInputStream
:用于从内存中的字节数组读取数据。BufferedInputStream
:提供了缓冲功能,提高了读取效率。DataInputStream
:用于从输入流中按照基本数据类型进行数据读取。
import java.io.*; public class InputStream示例 { public static void main(String[] args) { try { // FileInputStream: 从文件读取数据 FileInputStream fileInputStream = new FileInputStream("example.txt"); int byteRead; System.out.println("使用FileInputStream从文件中读取数据:"); while ((byteRead = fileInputStream.read()) != -1) { System.out.print((char) byteRead); } fileInputStream.close(); // ByteArrayInputSteam: 从字节数组读取数据 byte[] byteArray = { 65, 66, 67, 68, 69 }; ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArray); System.out.println("\n\n使用ByteArrayInputStream从字节数组中读取数据:"); int byteReadFromByteArray; while ((byteReadFromByteArray = byteArrayInputStream.read()) != -1) { System.out.print((char) byteReadFromByteArray); } byteArrayInputStream.close(); // BufferedInputStream: 带缓冲地从文件读取数据 FileInputStream fileInputStream2 = new FileInputStream("example.txt"); BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream2); System.out.println("\n\n使用BufferedInputStream从文件中读取数据:"); int byteReadBuffered; while ((byteReadBuffered = bufferedInputStream.read()) != -1) { System.out.print((char) byteReadBuffered); } bufferedInputStream.close(); // DataInputStream: 从文件读取基本数据类型 FileInputStream fileInputStream3 = new FileInputStream("example.txt"); DataInputStream dataInputStream = new DataInputStream(fileInputStream3); System.out.println("\n\n使用DataInputStream从文件中读取数据类型:"); System.out.println("整数: " + dataInputStream.readInt()); System.out.println("双精度数: " + dataInputStream.readDouble()); dataInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } }
在这个示例中:
- 使用
FileInputStream
从文件 (example.txt
) 中读取数据。- 使用
ByteArrayInputStream
从字节数组 (byteArray
) 中读取数据。- 使用
BufferedInputStream
带缓冲地从文件读取数据,这提高了效率。- 使用
DataInputStream
从文件中读取基本数据类型。请注意,这需要文件以兼容的格式使用DataOutputStream
写入。
OutputStream字节输出流
OutputStream
是 Java 中用于处理字节输出流的抽象类。它是所有字节输出流类的父类,提供了一些基本的方法来写入字节数据。
以下是 OutputStream
类的一些主要方法和说明:
-
void write(int b)
:- 将指定的字节写入输出流。
- 参数
b
是要写入的字节的整数表示,只写入b
的最低 8 位。
-
void write(byte[] b)
:- 将字节数组
b
中的所有字节写入输出流。
- 将字节数组
-
void write(byte[] b, int off, int len)
:- 将字节数组
b
中从偏移量off
开始的len
个字节写入输出流。
- 将字节数组
-
void flush()
:- 刷新输出流,强制将缓冲区中的数据写入目的地。
- 在某些输出流中(如缓冲流),数据可能会被缓冲,调用
flush()
方法可以确保数据被写入。
-
void close()
:- 关闭输出流并释放与之相关的资源。
import java.io.*; public class OutputStreamExample { public static void main(String[] args) { try { // 创建一个 FileOutputStream 对象来写入文件 OutputStream outputStream = new FileOutputStream("example.txt"); // 写入字符数据到文件 String data = "Hello, World!"; byte[] bytes = data.getBytes(); // 将字符串转换为字节数组 outputStream.write(bytes); // 写入字节数组到输出流 // 刷新输出流,确保数据被写入文件 outputStream.flush(); // 关闭输出流 outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } }
在这个示例中,我们使用
FileOutputStream
来创建一个OutputStream
对象,然后通过write(byte[] b)
方法将字节数组中的数据写入文件中。我们首先将字符串转换为字节数组,然后调用write()
方法将字节数组写入输出流。最后,我们调用
flush()
方法来刷新输出流,确保所有数据都被写入文件,并在finally
块中调用close()
方法来关闭输出流,以释放相关资源。
OutputStream
是一个抽象类,不能直接实例化,常用的实现类包括:
FileOutputStream
:用于向文件中写入数据。ByteArrayOutputStream
:用于向内存中的字节数组写入数据。BufferedOutputStream
:提供了缓冲功能,提高了写入效率。DataOutputStream
:用于向输出流中按照基本数据类型进行数据写入。
下面是一个示例代码,演示了如何使用这些输出流类:
import java.io.*; public class OutputStream示例 { public static void main(String[] args) { try { // FileOutputStream: 向文件中写入数据 FileOutputStream fileOutputStream = new FileOutputStream("example.txt"); String dataToFile = "Hello, World!"; fileOutputStream.write(dataToFile.getBytes()); // 写入字符串到输出流 fileOutputStream.close(); // ByteArrayOutputStream: 向内存中的字节数组写入数据 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); String dataToByteArray = "Welcome to Java!"; byteArrayOutputStream.write(dataToByteArray.getBytes()); // 写入字符串到字节数组 byte[] byteArray = byteArrayOutputStream.toByteArray(); // 获取写入的字节数组 System.out.println("从内存中的字节数组读取的数据: " + new String(byteArray)); byteArrayOutputStream.close(); // BufferedOutputStream: 提供了缓冲功能,提高了写入效率 FileOutputStream fileOutputStream2 = new FileOutputStream("example.txt"); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream2); String dataToBufferedStream = "BufferedOutputStream示例"; bufferedOutputStream.write(dataToBufferedStream.getBytes()); // 写入字符串到缓冲输出流 bufferedOutputStream.close(); // DataOutputStream: 向输出流中按照基本数据类型进行数据写入 FileOutputStream fileOutputStream3 = new FileOutputStream("data.dat"); DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream3); int intValue = 123; double doubleValue = 456.789; dataOutputStream.writeInt(intValue); // 写入整数到输出流 dataOutputStream.writeDouble(doubleValue); // 写入双精度数到输出流 dataOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } }
在这个示例中:
- 使用
FileOutputStream
向文件 (example.txt
) 中写入数据。- 使用
ByteArrayOutputStream
向内存中的字节数组写入数据,并将其转换为字符串输出。- 使用
BufferedOutputStream
提供了缓冲功能,以提高写入效率,示例中写入了一个字符串到文件中。- 使用
DataOutputStream
向输出流中按照基本数据类型进行数据写入,并将其保存到文件 (data.dat
) 中。
二、字符流
以字符为单位进行数据传输 ,适用于处理文本数据,并能按照指定字符编码进行转换。
Reader字符输入流
Reader
是 Java 中用于处理字符输入流的抽象类。它是所有字符输入流类的父类,提供了一些基本的方法来读取字符数据。
以下是 Reader
类的一些主要方法和说明:
-
int read()
:- 读取输入流中的下一个字符,并返回其 Unicode 值(0~65535),如果已经到达输入流的末尾,则返回 -1。
- 如果读取的字符为负数,则表示到达了输入流的末尾。
-
int read(char[] cbuf)
:- 从输入流中读取多个字符,并将其存储到字符数组
cbuf
中。 - 返回实际读取的字符数,如果已经到达输入流的末尾,则返回 -1。
- 从输入流中读取多个字符,并将其存储到字符数组
-
int read(char[] cbuf, int off, int len)
:- 从输入流中读取多个字符,并将其存储到字符数组
cbuf
中,从偏移量off
开始存储,最多读取len
个字符。 - 返回实际读取的字符数,如果已经到达输入流的末尾,则返回 -1。
- 从输入流中读取多个字符,并将其存储到字符数组
-
long skip(long n)
:- 跳过输入流中的
n
个字符,返回实际跳过的字符数。 - 注意:该方法不保证一定成功跳过
n
个字符,可能会跳过比n
少的字符。
- 跳过输入流中的
-
void close()
:- 关闭输入流并释放与之相关的资源。
import java.io.*; public class ReaderExample { public static void main(String[] args) { try { // 创建一个 FileReader 对象来读取文件 Reader reader = new FileReader("example.txt"); // 读取文件中的字符数据 int data; while ((data = reader.read()) != -1) { // 将读取的字符数据转换为字符并打印出来 System.out.print((char) data); } // 关闭输入流 reader.close(); } catch (IOException e) { e.printStackTrace(); } } }
在这个示例中,我们使用
FileReader
来创建一个Reader
对象,然后通过read()
方法逐个字符地读取文件中的数据,直到到达文件末尾(read()
方法返回 -1)。每次读取到一个字符后,我们将其转换为字符并打印出来。与之前的示例类似,我们在
finally
块中调用close()
方法来关闭输入流,以确保资源得到正确释放。
Reader
是一个抽象类,不能直接实例化,常用的实现类包括:
FileReader
:用于从文件中读取字符数据。CharArrayReader
:用于从字符数组中读取字符数据。BufferedReader
:提供了缓冲功能,提高了读取效率,并且可以按行读取数据。InputStreamReader
:可以将字节输入流转换为字符输入流,同时指定字符编码。
以下是使用这些字符输入流类的示例代码:
import java.io.*; public class Reader示例 { public static void main(String[] args) { try { // FileReader: 从文件中读取字符数据 FileReader fileReader = new FileReader("example.txt"); int charRead; System.out.println("使用FileReader从文件中读取数据:"); while ((charRead = fileReader.read()) != -1) { System.out.print((char) charRead); } fileReader.close(); // CharArrayReader: 从字符数组中读取字符数据 char[] charArray = {'A', 'B', 'C', 'D', 'E'}; CharArrayReader charArrayReader = new CharArrayReader(charArray); System.out.println("\n\n使用CharArrayReader从字符数组中读取数据:"); int charReadFromArray; while ((charReadFromArray = charArrayReader.read()) != -1) { System.out.print((char) charReadFromArray); } charArrayReader.close(); // BufferedReader: 带缓冲地从文件读取数据,提高了读取效率,并且可以按行读取数据 FileReader fileReader2 = new FileReader("example.txt"); BufferedReader bufferedReader = new BufferedReader(fileReader2); System.out.println("\n\n使用BufferedReader从文件中读取数据:"); String line; while ((line = bufferedReader.readLine()) != null) { System.out.println(line); } bufferedReader.close(); // InputStreamReader: 将字节输入流转换为字符输入流,同时指定字符编码 FileInputStream fileInputStream = new FileInputStream("example.txt"); InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "UTF-8"); System.out.println("\n\n使用InputStreamReader从字节输入流中读取数据:"); int charReadFromInputStream; while ((charReadFromInputStream = inputStreamReader.read()) != -1) { System.out.print((char) charReadFromInputStream); } inputStreamReader.close(); } catch (IOException e) { e.printStackTrace(); } } }
在这个示例中:
- 使用
FileReader
从文件 (example.txt
) 中读取字符数据。- 使用
CharArrayReader
从字符数组 (charArray
) 中读取字符数据。- 使用
BufferedReader
提供了缓冲功能,以提高读取效率,并且按行读取数据。- 使用
InputStreamReader
将字节输入流转换为字符输入流,同时指定字符编码(这里指定为 UTF-8)。
Writer字符输出流
Writer
是 Java 中用于处理字符输出流的抽象类。它是所有字符输出流类的父类,提供了一些基本的方法来写入字符数据。
以下是 Writer
类的一些主要方法和说明:
-
void write(int c)
:- 将指定的字符写入输出流。
-
void write(char[] cbuf)
:- 将字符数组
cbuf
中的所有字符写入输出流。
- 将字符数组
-
void write(char[] cbuf, int off, int len)
:- 将字符数组
cbuf
中从偏移量off
开始的len
个字符写入输出流。
- 将字符数组
-
void write(String str)
:- 将字符串
str
中的所有字符写入输出流。
- 将字符串
-
void write(String str, int off, int len)
:- 将字符串
str
中从偏移量off
开始的len
个字符写入输出流。
- 将字符串
-
void flush()
:- 刷新输出流,强制将缓冲区中的数据写入目的地。
- 在某些输出流中(如缓冲流),数据可能会被缓冲,调用
flush()
方法可以确保数据被写入。
-
void close()
:- 关闭输出流并释放与之相关的资源。
import java.io.*; public class WriterExample { public static void main(String[] args) { try { // 创建一个 FileWriter 对象来写入文件 Writer writer = new FileWriter("example.txt"); // 写入字符数据到文件 String data = "Hello, World!"; writer.write(data); // 写入字符串到输出流 // 刷新输出流,确保数据被写入文件 writer.flush(); // 关闭输出流 writer.close(); } catch (IOException e) { e.printStackTrace(); } } }
在这个示例中,我们使用
FileWriter
来创建一个Writer
对象,然后通过write(String str)
方法将字符串写入文件中。我们直接调用write()
方法将字符串写入输出流。最后,我们调用
flush()
方法来刷新输出流,确保所有数据都被写入文件,并在finally
块中调用close()
方法来关闭输出流,以释放相关资源。
Writer
是一个抽象类,不能直接实例化,常用的实现类包括:
FileWriter
:用于向文件中写入字符数据。CharArrayWriter
:用于向字符数组中写入字符数据。BufferedWriter
:提供了缓冲功能,提高了写入效率,并且可以按行写入数据。OutputStreamWriter
:可以将字节输出流转换为字符输出流,同时指定字符编码。
以下是使用这些字符输出流类的示例代码:
import java.io.*; public class Writer示例 { public static void main(String[] args) { try { // FileWriter: 向文件中写入字符数据 FileWriter fileWriter = new FileWriter("example.txt"); String dataToFile = "Hello, World!"; fileWriter.write(dataToFile); // 写入字符串到输出流 fileWriter.close(); // CharArrayWriter: 向字符数组中写入字符数据 CharArrayWriter charArrayWriter = new CharArrayWriter(); String dataToCharArray = "Welcome to Java!"; charArrayWriter.write(dataToCharArray); // 写入字符串到字符数组 char[] charArray = charArrayWriter.toCharArray(); // 获取写入的字符数组 System.out.println("从字符数组中读取的数据: " + new String(charArray)); charArrayWriter.close(); // BufferedWriter: 提供了缓冲功能,提高了写入效率,并且可以按行写入数据 FileWriter fileWriter2 = new FileWriter("example.txt"); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter2); String dataToBufferedStream = "BufferedWriter示例"; bufferedWriter.write(dataToBufferedStream); // 写入字符串到缓冲输出流 bufferedWriter.close(); // OutputStreamWriter: 将字节输出流转换为字符输出流,同时指定字符编码 FileOutputStream fileOutputStream = new FileOutputStream("example.txt"); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "UTF-8"); String dataToOutputStream = "OutputStreamWriter示例"; outputStreamWriter.write(dataToOutputStream); // 写入字符串到输出流 outputStreamWriter.close(); } catch (IOException e) { e.printStackTrace(); } } }
在这个示例中:
- 使用
FileWriter
向文件 (example.txt
) 中写入字符数据。- 使用
CharArrayWriter
向字符数组中写入字符数据,并将其转换为字符串输出。- 使用
BufferedWriter
提供了缓冲功能,以提高写入效率,并且示例中写入了一个字符串到文件中。- 使用
OutputStreamWriter
将字节输出流转换为字符输出流,并指定字符编码(这里指定为 UTF-8)。
三、 信息存储最小单位都是字节,那为什么IO流要分为字节流和字符流呢?
因为字节流如果我们不知道编码的话就容易乱码,所有干脆提供了一个直接操作字符的接口
常见编码:
utf8
:英文占 1 字节,中文占 3 字节;
unicode
:任何字符都占 2 个字节;
gbk
:英文占 1 字节,中文占 2 字节。
四、打印流
打印流(PrintStream 和 PrintWriter)是 Java 中用于将数据格式化输出到目的地的类,它们提供了方便的方法来打印各种数据类型的值,并且可以自动刷新缓冲区。
-
PrintStream:
PrintStream
是处理字节流的打印类,可以向输出流打印各种数据类型的值,并且支持自动刷新缓冲区。- 常见的构造方法包括:
PrintStream(OutputStream out)
:使用指定的输出流创建PrintStream
对象。PrintStream(String fileName)
:使用指定的文件名创建PrintStream
对象。
-
PrintWriter:
PrintWriter
是处理字符流的打印类,功能类似于PrintStream
,但是针对字符流。- 常见的构造方法包括:
PrintWriter(File file)
:使用指定的文件创建PrintWriter
对象。PrintWriter(OutputStream out)
:使用指定的输出流创建PrintWriter
对象。PrintWriter(String fileName)
:使用指定的文件名创建PrintWriter
对象。
这些类提供了一系列重载的 print
和 println
方法,可以用于打印各种类型的数据,并且可以按照格式化的方式进行输出。此外,它们还提供了一些其他的方法,如 format
和 printf
,用于按照指定的格式输出数据。
下面是一个简单的示例代码,演示了如何使用
PrintStream
和PrintWriter
打印数据:import java.io.*; public class PrintStreamPrintWriterExample { public static void main(String[] args) { try { // 使用 PrintStream 打印数据到控制台 PrintStream printStream = new PrintStream(System.out); printStream.println("This is a message printed using PrintStream."); printStream.printf("The value of pi is: %.2f%n", Math.PI); printStream.close(); // 使用 PrintWriter 打印数据到文件 PrintWriter printWriter = new PrintWriter("output.txt"); printWriter.println("This is a message printed using PrintWriter."); printWriter.printf("The value of e is: %.4f%n", Math.E); printWriter.close(); } catch (IOException e) { e.printStackTrace(); } } }
在这个示例中,我们使用
PrintStream
打印数据到控制台,并使用PrintWriter
打印数据到文件。