目录
前言:
1.缓冲流:
2.转换流:
3.序列化流:
4.打印流:
5.压缩流:
总结:
在前面我们从IO流体系出发,分别介绍了字节流和字符流,并且详细讲解了其下沿的各种基本流,而在今天我们就要学习一下IO流中的几个高级流。
缓冲流其实就是可以让我们自己手动提供缓冲区,以此来增加读写速度,我们知道字节流是没有缓冲区的,因此创建一个缓冲区对于字节流的读写速度提高是很明显的。
缓冲区是计算机科学中常用的一个概念,用于在不同速度的系统或设备之间传输数据时解决速度不匹配的问题。它是用来临时存储数据的一段内存区域,可用于暂时保存输入数据、输出数据或处理中间数据。
缓冲区通常用于处理输入/输出(I/O)操作,例如在文件读写、网络通信、图像处理等过程中。它能够提高数据传输的效率,减少因速度不匹配而导致的延迟和性能瓶颈。
总结来说,缓冲区是一种临时存储数据的内存区域,可以解决不同速度设备之间数据传输的速度不匹配问题,提高系统的效率。它在输入/输出操作和数据处理过程中起到关键的作用。
示例代码:
import java.io.*;
public class ByteStreamExample {
public static void main(String[] args) {
try {
// 创建字节输入流
FileInputStream fileInputStream = new FileInputStream("input.txt");
// 使用字节缓冲流包装字节输入流
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
// 创建字节输出流
FileOutputStream fileOutputStream = new FileOutputStream("output.txt");
// 使用字节缓冲流包装字节输出流
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
// 读取文件内容并写入到目标文件
int data;
while ((data = bufferedInputStream.read()) != -1) {
bufferedOutputStream.write(data);
}
// 关闭流
bufferedInputStream.close();
bufferedOutputStream.close();
System.out.println("文件复制成功");
} catch (IOException e) {
e.printStackTrace();
}
}
}
字节缓冲流的底层默认就自带了一个长度为8192的缓冲区,这在我们一开始学习到的基本字节流中是没有的。但其实字节缓冲流本质上只是对基本字节流的一个包装,在读取数据的时候依然是基本字节流在读取数据,并不是什么新的方法。
示例代码:
import java.io.*;
public class CharacterStreamExample {
public static void main(String[] args) {
try {
// 创建字符输入流
FileReader fileReader = new FileReader("input.txt");
// 使用字符缓冲流包装字符输入流
BufferedReader bufferedReader = new BufferedReader(fileReader);
// 创建字符输出流
FileWriter fileWriter = new FileWriter("output.txt");
// 使用字符缓冲流包装字符输出流
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
// 读取文件内容并写入到目标文件
String line;
while ((line = bufferedReader.readLine()) != null) {
bufferedWriter.write(line);
bufferedWriter.newLine();
}
// 关闭流
bufferedReader.close();
bufferedWriter.close();
System.out.println("文件复制成功");
} catch (IOException e) {
e.printStackTrace();
}
}
}
虽然基本的字符流方法就自带缓冲区,但是我们缓冲字符流也提供了一些很好的方法来便捷我们的使用。
readLine在读取方法时候,一次读一整行,遇到回车换行就结束
但是他不会把回车换行读到内存中
缓冲流的优点:
1. 提高读写性能:缓冲流通过在内存中创建缓冲区,减少IO操作的次数,从而提高读写性能。它们可以一次读取或写入多个字节或字符,减少了与磁盘或网络的交互次数。
2. 减少系统开销:使用缓冲流可以减少系统调用次数和CPU的使用率。通过将数据保存在内存中的缓冲区中,在进行大规模数据读写时,可以显著降低系统开销和资源消耗。
3. 支持高效的字符处理:字符缓冲流(BufferedReader和BufferedWriter)提供了方便的方法,比如一次读取一行字符数据或一次写入一行字符数据。这对于处理文本文件非常有用,可以简化代码并提高代码的可读性。
4. 缓冲区自动管理:缓冲流会自动管理缓冲区的大小和数据的填充和清空,无需手动处理。这样可以简化代码编写,并提高代码的可维护性。
5. 可以与其他IO流结合使用:缓冲流可以与其他各种字节流或字符流结合使用,如文件流、网络流等。这使得在不同场景下进行读写操作更加灵活和高效。
转换流(InputStreamReader和OutputStreamWriter)是Java IO库中的字符流,用于在字节流和字符流之间进行转换。它们提供了将字节流转换为字符流的能力,以便更方便地处理文本数据。
转换流的主要作用是解决字节流和字符流之间的编码转换问题。在读取或写入文本数据时,需要将字节数据转换为字符数据或将字符数据转换为字节数据。转换流在内部实现了字符集的转换,可以根据指定的字符集将字节流转换为字符流,或将字符流转换为字节流。
转换流的构造函数接受两个参数:字节流和字符集。其中,字节流可以是字节输入流或字节输出流,而字符集可以是标准字符集名称或特定字符集名称。
主要的转换流类及其作用如下:
import java.io.*;
public class InputStreamReaderExample {
public static void main(String[] args) {
try {
FileInputStream fileInputStream = new FileInputStream("input.txt");
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "UTF-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
bufferedReader.close();
inputStreamReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.*;
public class OutputStreamWriterExample {
public static void main(String[] args) {
try {
FileOutputStream fileOutputStream = new FileOutputStream("output.txt");
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "UTF-8");
BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
bufferedWriter.write("Hello, World!");
bufferedWriter.newLine();
bufferedWriter.write("你好,世界!");
bufferedWriter.close();
outputStreamWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
通过使用转换流,我们可以在字节流和字符流之间进行方便的转换,使得处理文本数据更加简便和灵活。转换流还支持指定字符集,以便进行特定编码的读写操作。
转换流的存在主要是为了:让字节流使用字符流中的方法。
其实在以前,我们还可以利用转换流来使得读取文件的时候按照指定的字符编码读取。
序列化流是Java IO库中的一种特殊流,用于将对象转换为字节序列,以便存储到文件、数据库或通过网络进行传输。它们提供了对象的序列化和反序列化功能,使得可以方便地将对象持久化或在不同系统之间传输对象数据。
java中的序列化和反序列化是通过ObjectInputStream和ObjectOutputStream类来实现的,它们是字节流的子类,用于处理对象的读写操作。
序列化流的主要作用有以下几点:
对象的持久化:通过将对象转换为字节序列,可以将对象永久保存到磁盘上。这样即使程序结束,对象数据也可以被重新读取和使用。对象的持久化在很多场景中非常有用,比如保存用户信息、游戏进度等。
对象的传输:通过序列化流,可以将对象转换为字节序列,然后发送到网络上或通过进程间通信进行传输。接收方可以使用反序列化将字节序列转换回对象,以便获取传输的对象数据。这在分布式系统、远程方法调用等场景中非常常见。
序列化流的用法包括以下几个步骤:
try {
FileOutputStream fileOut = new FileOutputStream("object.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(object);
out.close();
fileOut.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
FileInputStream fileIn = new FileInputStream("object.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
Object object = in.readObject();
in.close();
fileIn.close();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
在进行对象的序列化和反序列化时,需要注意以下事项:
使用序列化的注意点:
1. 类的版本控制:当你使用序列化流将对象写入文件时,类的定义可能会发生变化。为了确保在反序列化过程中能够正确地读取对象,你需要仔细控制类的版本。你可以使用 `serialVersionUID` 字段来指定类的版本号,并在类的变化过程中进行更新。
不过我们可以手动设置让idea能对此进行提示,方便我们快捷生成serialVersionUID
2. 数据完整性:序列化流允许你将整个对象图写入文件,包括对象之间的引用。然而,这也意味着你需要确保所有相关的对象都被正确地序列化和反序列化,以保持数据的完整性。如果某个对象没有被序列化或者反序列化,那么它在反序列化后可能会变成 `null` 或者其他未初始化的值。
3. 安全性考虑:序列化流允许你将对象写入文件并从文件中读取。这可能引发安全问题,因为恶意用户可能会修改序列化的数据。为了确保安全性,你应该对序列化的数据进行验证和过滤,以防止不可预测的行为。
4. 跨语言兼容性:序列化是一种用于对象持久化和传输的通用机制。然而,不同的编程语言可能会使用不同的序列化格式和机制。如果你计划在不同的编程语言之间进行对象的序列化和反序列化,你需要确保选择一个与目标编程语言兼容的序列化方式。
5. 性能问题:序列化和反序列化过程可能会占用大量的时间和资源。如果你需要频繁地将大量对象进行序列化和反序列化操作,你可能需要考虑性能优化方面的问题,例如使用更快速的序列化库或者改变序列化策略。、
总结来说,序列化流在Java IO库中是一种特殊的流,用于对象的序列化和反序列化操作,实现了对象的持久化和传输功能。通过序列化和反序列化,我们可以方便地将对象转换为字节序列,进行持久化存储或跨系统传输。
打印流是Java IO库中的一种流,用于将数据以文本形式输出到控制台或文件。它提供了简洁易用的打印方法,方便用户进行输出操作。
Java中的打印流有两种主要的实现类:PrintStream和PrintWriter。
PrintStream:
PrintStream是字节打印流,它继承自OutputStream类,并且提供了一系列打印方法,例如print、println等。PrintStream可以接收字节数据,并将其转换为字符输出,它还具备自动刷新和在操作完成后关闭的能力。
PrintWriter:
PrintWriter是字符打印流,它继承自Writer类,也提供了一系列打印方法。PrintWriter可以接收字符数据,并将其直接输出到目标,它也具备自动刷新和在操作完成后关闭的能力。
打印流的主要优点在于它们的简化和便利性,使用打印流可以更方便地进行输出操作,而不需要手动进行转换和拼接字符串。打印流的常见用法包括以下几点:
PrintStream ps = System.out;
PrintWriter pw = new PrintWriter(System.out);
ps.print("Hello");
pw.println(12345);
ps.println(3.14);
pw.print(true);
pw = new PrintWriter(System.out, true); // 设置自动刷新
pw.println("Auto flush");
自动刷新这个函数虽然PrintStream也有,但是我们不会使用,因为字节流底层就没有缓冲区,开不开自动刷新都一样。
ps.close();
pw.close();
总结来说,打印流是Java IO库中方便的输出流,它提供了打印各种数据类型的方法,并具备自动刷新和关闭的功能。使用打印流可以简化输出操作,减少手动转换和拼接字符串的工作量。
压缩流和解压缩流是Java IO库中用于对数据进行压缩和解压缩的特殊流,它们可以用于减小文件大小、提高网络传输效率以及节省存储空间。压缩流用于将数据压缩成较小的字节序列,而解压缩流则用于将压缩后的字节序列还原成原始的数据。
在Java中,压缩流和解压缩流是通过GZIP压缩算法实现的,主要包括以下两个类:
压缩的代码示例:
try {
FileOutputStream fileOut = new FileOutputStream("compressed.gz");
GZIPOutputStream gzipOut = new GZIPOutputStream(fileOut);
gzipOut.write(data);
gzipOut.close();
fileOut.close();
} catch (IOException e) {
e.printStackTrace();
}
解压缩的代码示例:
try {
FileInputStream fileIn = new FileInputStream("compressed.gz");
GZIPInputStream gzipIn = new GZIPInputStream(fileIn);
byte[] buffer = new byte[1024];
int length;
while ((length = gzipIn.read(buffer)) != -1) {
// 处理解压缩后的数据
}
gzipIn.close();
fileIn.close();
} catch (IOException e) {
e.printStackTrace();
}
压缩流和解压缩流的使用需要注意以下几点:
总结来说,压缩流和解压缩流是Java IO库中用于对数据进行压缩和解压缩的特殊流。通过GZIPOutputStream可以将数据压缩成GZIP格式的字节序列,而通过GZIPInputStream可以将压缩后的字节序列解压缩成原始数据。在使用压缩流和解压缩流时,需要将其连接到其他流,并注意关闭流以释放资源。
本文我们为大家介绍了这些IO流中的高级类,他们各自都有各自的最佳使用范围,我们可以根据自己的需求来选择到底使用哪一个高级类完成需求,而这些其实在日常中不是很普遍的使用,因此我们只需要知道这些东西,需要用的时候即用即查就好了。
如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!