一、打印流(PrintStream[字节]、PrintWriter[字符])
(基本上可以代替前面所学的字节、字符输出流),二者关于打印数据功能相同(都方便且高效),但是关于数据写出不同,前者写出字节数据,后者写出字符数据。
1.什么是打印流?
打印流可以实现更方便、更高效的打印数据作用,能实现打印什么就写出什么
2.打印流的作用是什么?
实现更方便、更高效的打印数据,自动刷新输出缓冲区,以字符串形式打印到文件
3.打印流提供打印数据的方案?
4.打印流怎么用?
1)创建一个打印流管道对象
2)用对象调用方法
注意:以上是一般情况下,打印流的使用方法。那么,如果想要在文件后追加数据呢?此时就不能和低级流那样直接在后面跟上true。此时,应该在打印流中包装一个低级流(这个低级流需要new出来)并在低级流中跟上true。
5.打印流的一种应用:
输出语句的重定向(依赖于方法:setOut(输出流)方法 )
示例:
import java.io.FileOutputStream;
import java.io.PrintStream;
public class PrintStreamRedirectExample {
public static void main(String[] args) {
// 创建文件输出流,并将标准输出流重定向到文件
PrintStream ps = new PrintStream(new FileOutputStream("output.txt"));
System.setOut(ps);
// 输出到重定向后的文件
System.out.println("Hello, World!");
System.out.println("This is a test.");
// 恢复原来的标准输出流
System.setOut(System.out);
// 输出到控制台
System.out.println("This will be printed to console.");
}
}
二、数据流(字节流下的两种实现类)
问题:如果使用上面的打印流打印数据到文件中,我们怎么读取出特定类型的数据呢?
答:打印流打印的数据被当作字符串堆砌到文件中,无法读取出特定类型的数据,因此我们需要一种新的流来同时写出数据和数据类型,以便我们在读取时,读取到特定类型的数据。
1.什么是数据流?
DataOutPutStream(数据输出流)、DataInputStream(数据输入流)
2.数据流的作用是什么?
同时写出数据和数据类型,以便我们在读取时,读取到特定类型的数据。
3.数据流提供打印数据的方案?
DataOutPutStream(数据输出流)
DataInputStream(数据输入流)
4.数据流怎么用?
1)创建一个数据流管道对象(其中参数需要包装低级的字节输入输出流)
2)用对象调用方法
注意:在使用数据输出流时,需要注意读取顺序应该和写入顺序相同!!!!
//数据输出流示例程序:
import java.io.*;
public class DataOutputStreamExample {
public static void main(String[] args) {
try {
// 创建File对象,指定要写入的文件路径
File outputFile = new File("output.txt");
// 创建DataOutputStream,包装FileOutputStream
DataOutputStream dos = new DataOutputStream(new FileOutputStream(outputFile));
// 写入数据
dos.writeInt(123); // 写入一个整数
dos.writeFloat(3.14f); // 写入一个浮点数
dos.writeUTF("Hello, World!"); // 写入一个字符串
// 关闭DataOutputStream
dos.close();
System.out.println("Data written to file successfully.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
//数据输入流的示例程序:
import java.io.*;
public class DataInputStreamExample {
public static void main(String[] args) {
try {
// 创建File对象,指定要读取的文件路径
File inputFile = new File("output.txt");
// 创建DataInputStream,包装FileInputStream
DataInputStream dis = new DataInputStream(new FileInputStream(inputFile));
// 读取数据
int intValue = dis.readInt(); // 读取一个整数
float floatValue = dis.readFloat(); // 读取一个浮点数
String stringValue = dis.readUTF(); // 读取一个字符串
// 关闭DataInputStream
dis.close();
// 打印读取的数据
System.out.println("Read integer: " + intValue);
System.out.println("Read float: " + floatValue);
System.out.println("Read string: " + stringValue);
} catch (IOException e) {
e.printStackTrace();
}
}
}
三、(重点)序列化流
问题:上面提到的数据流可以读写出指定的类型的数据,那么怎么读取一个一个的对象呢?那么就需要一种新的流:序列化流
1. 什么是序列化流?
序列化流是Java I/O系统中的一种流,它允许将对象转换为字节流,以便可以将其存储到文件、数据库或通过网络传输。Java中的序列化流主要包括ObjectOutputStream
和ObjectInputStream
。ObjectOutputStream
用于将对象序列化为字节流,而ObjectInputStream
用于从字节流中反序列化恢复对象。
2. 序列化流的作用是什么?
序列化流的主要作用包括:
- 持久化对象状态:将对象的状态保存到文件或其他持久化存储中,以便在程序重启后可以恢复对象的状态。
- 对象传输:通过网络传输对象,使得分布式系统中的不同部分可以共享对象状态。
- 对象复制:创建对象的副本,这在某些情况下可以用于克隆对象。
3. 序列化流提供的方案:
Java序列化流提供的方案包括:
- 对象序列化:使用
ObjectOutputStream
将对象转换为字节序列。 - 对象反序列化:使用
ObjectInputStream
从字节序列中恢复对象。 - 版本控制:Java序列化机制支持版本控制,即使类定义发生了变化,只要变化是兼容的,反序列化仍然可以成功。
- 自定义序列化:允许开发者通过实现
writeObject
和readObject
方法来自定义序列化和反序列化的行为。
4. 序列化流怎么用?
使用序列化流的基本步骤如下:
序列化对象(使用ObjectOutputStream
):
- 创建一个
FileOutputStream
,指向一个文件,用于存储序列化后的对象。 - 创建一个
ObjectOutputStream
,将其连接到FileOutputStream
。 - 使用
ObjectOutputStream
的writeObject
方法将对象写入流中。 - 关闭
ObjectOutputStream
。
示例代码:
import java.io.*;
public class SerializationExample {
public static void main(String[] args) {
try {
// 创建一个对象
MySerializableObject obj = new MySerializableObject("Example Object");
// 创建FileOutputStream
FileOutputStream fileOut = new FileOutputStream("object.ser");
// 创建ObjectOutputStream
ObjectOutputStream out = new ObjectOutputStream(fileOut);
// 序列化对象
out.writeObject(obj);
// 关闭流
out.close();
fileOut.close();
System.out.println("Object has been serialized");
} catch (IOException e) {
e.printStackTrace();
}
}
}
反序列化对象(使用ObjectInputStream
):
- 创建一个
FileInputStream
,指向包含序列化对象的文件。 - 创建一个
ObjectInputStream
,将其连接到FileInputStream
。 - 使用
ObjectInputStream
的readObject
方法从流中读取对象。 - 关闭
ObjectInputStream
。
示例代码:
import java.io.*;
public class DeserializationExample {
public static void main(String[] args) {
try {
// 创建FileInputStream
FileInputStream fileIn = new FileInputStream("object.ser");
// 创建ObjectInputStream
ObjectInputStream in = new ObjectInputStream(fileIn);
// 反序列化对象
MySerializableObject obj = (MySerializableObject) in.readObject();
// 关闭流
in.close();
fileIn.close();
System.out.println("Object has been deserialized");
System.out.println(obj.getMessage());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
请注意,要序列化的类必须实现java.io.Serializable
接口,这是一个标记接口,没有定义任何方法。此外,如果类中有任何非瞬态(non-transient)和非静态(non-static)的字段是不可序列化的(例如,它们引用了不可序列化的类),那么这些字段必须声明为transient
,以避免序列化过程中的错误。(后面一句话简单的说就是:如果想要有选择性的序列化,就把不想序列化的部分用transient修饰)
四、io框架
框架怎么使用?下面以commons-io框架为演示:
以上就是这个框架为我们准备的一些完成某种目的的简便方法,极大的提高了io效率
那么,我们怎么获得框架呢?又怎么使用呢?
(前提是,这些框架是开源的)我们可以在相应的官网上下载框架(.zip文件),之后的步骤如图:包括怎么在IDE中导入框架,怎么把框架合并在我们的项目中供我们使用。