文章目录
一、前言
二、顺序流(合并流)
2.1 顺序流定义 / 合并流定义
JavaIO流——合并流/顺序流(SequenceInputStream):,就是把多个输入流,合并成一个流对象,且见代码1。
2.2 代码:顺序流/合并流
代码1——合并流:
package mypackage;
import java.io.FileInputStream;
import java.io.SequenceInputStream;
//合并流/顺序流(SequenceInputStream):
// 就是把多个输入流,合并成一个流对象.
public class Test {
public static void main(String[] args) throws Exception {
// 不同输入流有不同对应txt文件,将输入流合并后,合并后的输入流可以操作多个文件
SequenceInputStream sequenceInputStream = new SequenceInputStream(
new FileInputStream("stream1.txt"),
new FileInputStream("stream2.txt"));
byte[] buffer = new byte[1024];
int len = -1;
while ((len = sequenceInputStream.read(buffer)) != -1) {
System.out.println(new String(buffer, 0, len));
}
sequenceInputStream.close();
}
}
输出1:
Java程序员就业前景好,薪资高!
一起来学习Java吧!
小结1:
1、合并流对应的对象是输入流,是对输入流合并,不是对输出流合并;
2、合并的是两个输入流而不是两个源文件:因为不同输入流有不同对应txt文件,用合并流将两个输入流合并后,可以输入两个文件,所以说,合并的是两个输入流而不是两个源文件。
3、合并流可以接收合并流作为实际参数,形成多个流的合并,也称合并嵌套。
2.3 面试金手指:合并流/顺序流
合并流定义:JavaIO流——合并流,接收两个输入流作为参数,合并两个输入流或合并流,对外形成一个更大的流,方便客户端操作。
合并流需要注意的点:
1、合并流对应的对象是输入流,是对输入流合并,不是对输出流合并;
2、因为不同输入流有不同对应txt文件,用合并流将两个输入流合并后,可以输入两个文件,注意合并的是两个输入流而不是两个源文件。
3、合并流可以接收合并流作为实际参数,形成多个流的合并,也称合并嵌套。
三、对象流(序列化和反序列化)
3.1 对象流 提供一种 序列化/反序列化 的实现方式
1.1 序列化和反序列化定义:
序列化: 指把堆内存中的Java对象数据,通过某种方式把对象存储到磁盘文件中或者传递给其他网络的节点(在网络上传输). 我们把这个过程称之为序列化.
反序列化:把磁盘文件中的对象数据或者把网络节点上的对象数据,恢复成Java对象的过程.
1.2 为什么要做序列化:
1):在分布式系统中,需要共享的数据的JavaBean对象,都得做序列化,此时需要把对象再网络上传输,此时就得把对象数据转换为二进制形式.以后存储在HttpSession中的对象,都应该实现序列化接口(只有实现序列化接口的类,才能做序列化操作).
2):服务钝化:如果服务发现某些对象好久都没有活动了,此时服务器就会把这些内存中的对象,持久化在本地磁盘文件中(Java对象–>二进制文件). 如果某些对象需要活动的时候,现在内存中去寻找,找到就使用,找不到再去磁盘文件中,反序列化我们得对象数据,恢复成Java对象.
1.3 Java对象流——JavaIO流中实现序列化的方式
使用对象流来完成序列化和反序列化操作:
ObjectOutputStream: 通过writeObject方法做序列化操作的.
ObjectInputStream: 通过readObject方法做反序列化操作的.
ObjectOutputStream ObjectInputStream,提供一种序列化方式,序列化方式有很多,现在互联网大厂常用的是protobuf,最高效的系列化方式
3.2 代码:对象流
3.2.1 实体类 没有实现序列化接口
代码1:
package mypackage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
//对象流 ObjectInput
public class Test {
public static void main(String[] args) throws Exception {
File file = new File("object.txt");
writeObject(file);
readObject(file);
}
private static void writeObject(File file) throws Exception {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(file));
objectOutputStream.writeObject(new Person("小明", 12));
objectOutputStream.close();
}
private static void readObject(File file) throws Exception {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
Person person = (Person) objectInputStream.readObject();
System.out.println(person);
objectInputStream.close();
}
}
class Person { // 实体类没有实现序列化接口Serializable
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
输出1:
Exception in thread "main" java.io.NotSerializableException: mypackage.Person
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at mypackage.Test.writeObject(Test.java:20)
at mypackage.Test.main(Test.java:14)
小结1:因为实体类Person没有实现序列化接口Serializable,所以这里程序抛出异常java.io.NotSerializableException
3.2.2 实体类 序列化 + 不指定序列化版本号
代码2:
package mypackage1;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
//对象流 ObjectInput
public class Test {
public static void main(String[] args) throws Exception {
File file = new File("object.txt");
writeObject(file);
readObject(file);
}
private static void writeObject(File file) throws Exception {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(file));
objectOutputStream.writeObject(new Person("小明", 12));
objectOutputStream.close();
}
private static void readObject(File file) throws Exception {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
Person person = (Person) objectInputStream.readObject();
System.out.println(person);
objectInputStream.close();
}
}
class Person implements Serializable { // 和代码1的唯一不同,实体类实现Serializable接口
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
输出2:
Person [name=小明, age=12]
小结2:实体类Person实现序列化接口后,成功解决了程序异常,一般来说,随着项目的升级,系统的class文件也会升级(增加一个字段/删除一个字段), Java通过serialVersionUID(序列化版本号)来判断字节码是否发生改变.所以我们为实体类Person添加一个序列化版本号。
3.2.3 实体类 序列化 + 指定序列化版本号
代码3:
package mypackage2;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
//对象流 ObjectInput
public class Test {
public static void main(String[] args) throws Exception {
File file = new File("object.txt");
writeObject(file);
readObject(file);
}
private static void writeObject(File file) throws Exception {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(file));
objectOutputStream.writeObject(new Person("小明", 12));
objectOutputStream.close();
}
private static void readObject(File file) throws Exception {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
Person person = (Person) objectInputStream.readObject();
System.out.println(person);
objectInputStream.close();
}
}
class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
输出3:
Person [name=小明, age=12]
小结3:给实体类Person加上序列化版本号之后,整个问题正是解决。
3.3 面试金手指:对象流 提供一种 序列化/反序列化 的实现方式
1.1 序列化和反序列化定义:
序列化: 指把堆内存中的Java对象数据,通过某种方式把对象存储到磁盘文件中或者传递给其他网络的节点(在网络上传输). 我们把这个过程称之为序列化.
反序列化:把磁盘文件中的对象数据或者把网络节点上的对象数据,恢复成Java对象的过程.
1.2 为什么要做序列化:
1):在分布式系统中,需要共享的数据的JavaBean对象,都得做序列化,此时需要把对象再网络上传输,此时就得把对象数据转换为二进制形式.以后存储在HttpSession中的对象,都应该实现序列化接口(只有实现序列化接口的类,才能做序列化操作).
2):服务钝化:如果服务发现某些对象好久都没有活动了,此时服务器就会把这些内存中的对象,持久化在本地磁盘文件中(Java对象–>二进制文件). 如果某些对象需要活动的时候,现在内存中去寻找,找到就使用,找不到再去磁盘文件中,反序列化我们得对象数据,恢复成Java对象.
1.3 Java对象流——JavaIO流中实现序列化的方式
使用对象流来完成序列化和反序列化操作:
ObjectOutputStream: 通过writeObject方法做序列化操作的.
ObjectInputStream: 通过readObject方法做反序列化操作的.
ObjectOutputStream ObjectInputStream,提供一种序列化方式,序列化方式有很多,现在互联网大厂常用的是protobuf,最高效的系列化方式
代码1:因为实体类Person没有实现序列化接口Serializable,所以这里程序抛出异常java.io.NotSerializableException。
代码2:实体类Person实现序列化接口后,成功解决了程序异常,一般来说,随着项目的升级,系统的class文件也会升级(增加一个字段/删除一个字段), Java通过serialVersionUID(序列化版本号)来判断字节码是否发生改变.所以我们为实体类Person添加一个序列化版本号。
代码3:给实体类Person加上序列化版本号之后,整个问题正是解决。
JavaIO流——对象流通过writeObject()或readObject()实现序列化和反序列化,在磁盘读写和网络请求中保证数据的正确性。
四、与控制台相关:打印流 + 扫描流
4.1 打印流定义 + 扫描流定义
打印流定义:
打印到控制台;解释了System.out.println()底层原理,System.out.println();其实等价于 PrintStream ps = System.out; ps.println(),且见代码1;
扫描流定义:
与打印流对应,解释了控制到输入底层原理,本质上是java.util.Scanner类:扫描器类,表示输入操作,且见代码2。
4.2 代码:打印流 + 扫描流
4.2.1 打印流的使用
代码1——打印流:
package mypackage_打印流;
//System.out.println();其实等价于 PrintStream ps = System.out; ps.println()
//Java
public class Test {
public static void main(String[] args) {
String name = "小明";
int age = 12;
// 一般输出
System.out.println("name: " + name + " ,age: " + age);
// 打印流输出
String format = "name: %s ,age: %d";
Object[] data = { "小明", 12 };
System.out.printf(format, data);
System.out.println();
// 打印流简化输出
System.out.printf("name: %s ,age: %d", data);
}
}
输出1:
name: 小明 ,age: 12
name: 小明 ,age: 12
name: 小明 ,age: 12
小结1:打印流为Java提供了一种类似于C/C++的格式化打印,其实只是一种打印的补充格式。因为在Java语言中,System.out.println()通过+号重载可以实现字符串拼接,可以拼接出任何打印格式,所以说System.out.printf()只是提供了另一种打印格式的输出方式。
4.2.2 扫描流的使用
代码2——扫描流:
package mypackage_扫描类;
import java.util.Scanner;
//java.util.Scanner类:扫描器类,表示输入操作.
//存在的方法: xxx表示数据类型,如byte,int ,boolean等.
// boolean hasNextXxx():判断是否有下一种类型的数据
// Xxx nextXxx():获取下一个该类型的数据.
public class Test {
public static void main(String[] args) {
Scanner scanner = new Scanner("Java程序员就业前景好,薪资高!一起来学习Java吧!");
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(line);
}
scanner.close();
}
}
输出2:
Java程序员就业前景好,薪资高!一起来学习Java吧!
小结2:扫描类中,hasNextXxx()和nextXxx()两个方法,将字符串内容(也可以是其他内容txt、数组、boolean等)打印出来。
4.3 面试金手指:打印流 + 扫描流
打印流定义:
(1)打印到控制台;
(2)解释了System.out.println()底层原理,System.out.println();其实等价于 PrintStream ps =
System.out; ps.println(),且见代码1;
扫描流定义:
与打印流对应,解释了控制到输入底层原理,本质上是java.util.Scanner类:扫描器类,表示输入操作,且见代码2。
代码1:打印流为Java提供了一种类似于C/C++的格式化打印,其实只是一种打印的补充格式。因为在Java语言中,System.out.println()通过+号重载可以实现字符串拼接,可以拼接出任何打印格式,所以说System.out.printf()只是提供了另一种打印格式的输出方式。
代码2:扫描类中,hasNextXxx()和nextXxx()两个方法,将字符串内容(也可以是其他内容txt、数组、boolean等)打印出来。
注意:Java BIO流中,打印流用于打印到控制台,扫描流用于读入,甚至可将两个流放在一起写一个demo,可以尝试一下。
五、数据流:提供了可以读/写任意数据类型的方法
5.1 数据流定义:提供了可以读/写任意数据类型的方法,两个实现类,每个实现类都有writeXxx()和readXxx()方法
数据流定义:提供了可以读/写任意数据类型的方法,分别是:
DataOutputStream: 提供了 writeXxx(xxx value)方法.
DataInputStream: 提供了 readXxx()方法.
注意: writeXxx和readXxx必须要对应起来, writeByte写出的数据,此时只能使用readByte读取回来.且见代码1.
5.2 代码:数据流
代码1——数据流读写任意类型数据:
package mypackage;
//数据流,提供了可以读/写任意数据类型的方法:
//DataOutputStream: 提供了 writeXxx(xxx value)方法.
//DataInputStream: 提供了 readXxx()方法.
// 注意: writeXxx和readXxx必须要对应起来, writeByte写出的数据,此时只能使用readByte读取回来.
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class Test {
// 先写出到data.txt文件中去,然后再读入程序,再打印出来
public static void main(String[] args) throws Exception {
File file = new File("data.txt");
write(file);
read(file);
}
private static void read(File file) throws Exception {
DataInputStream dataInputStream = new DataInputStream(new FileInputStream(file));
System.out.println(dataInputStream.readByte());
System.out.println(dataInputStream.readChar());
System.out.println(dataInputStream.readUTF());
dataInputStream.close();
}
private static void write(File file) throws Exception {
DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream(file));
dataOutputStream.writeByte(12);
dataOutputStream.writeChar('男');
dataOutputStream.writeUTF("小明");
dataOutputStream.close();
}
}
输出1:
12
男
小明
小结1:理论上,数据流可以读写任意类型的数据,8种基本类型(boolean char float double byte short int long),字符串(readChars、readUTF),数组(int数组、byte数组),程序(代码1)为缩减程序,只写了三种(byte char utf字符串)。
5.3 面试金手指:数据流
数据流定义:提供了可以读/写任意数据类型的方法,两个实现类,每个实现类都有writeXxx()和readXxx()方法。
分别是:
DataOutputStream: 提供了 writeXxx(xxx value)方法.
DataInputStream: 提供了 readXxx()方法.
注意: writeXxx和readXxx必须要对应起来, writeByte写出的数据,此时只能使用readByte读取回来.且见代码1.
数据流的使用:提供了可以读/写任意数据类型的方法,任意数据类型是指8种基本类型(boolean char float double byte short int long),字符串(readChars、readUTF),数组(int数组、byte数组),均有相应的readXxx()和WriteXxx()方法。
六、管道流:实现两个线程之间的数据交互
6.1 管道流定义:实现两个线程之间的数据交互,四个实现类
Java管道流定义:实现两个线程之间的数据交互。
包括四种:管道字节输入流PipedInputStream、管道字节输出流PipedOutputStream、
管道字符输入流PipedReder、管道字符输出流PipedWriter。
6.2 代码:管道流
管道字节输入流PipedInputStream、管道字节输出流PipedOutputStream:
package mypackage;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
//管道流:实现两个线程之间的数据交互.
//PipedInputStream
//PipedOutputStream
//PipedReder
//PipedWriter
//ThreadA使用写出流不断写出,ThreadB中注入ThreadA引用,读取ThreadA写出流中的内容,不断打印到控制台
public class Test {
public static void main(String[] args) throws Exception {
ThreadA threadA = new ThreadA();
ThreadB threadB = new ThreadB(threadA);
threadA.start();
threadB.start();
}
}
class ThreadA extends Thread {
private PipedOutputStream pipedOutputStream = new PipedOutputStream();
public PipedOutputStream getOut() {
return pipedOutputStream;
}
@Override
public void run() { // run()方法中定义这个线程启动后具体干什么事情
try {
for (int i = 65; i < 65 + 26; i++) {
pipedOutputStream.write(i);
}
pipedOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
class ThreadB extends Thread {
PipedInputStream pipedInputStream = null;
public ThreadB(ThreadA threadA) throws Exception {
pipedInputStream = new PipedInputStream(threadA.getOut());
}
@Override
public void run() {
try {
int len = -1;
while ((len = pipedInputStream.read()) != -1) {
System.out.print((char) len);
}
pipedInputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出1:
ABCDEFGHIJKLMNOPQRSTUVWXYZ
1、新建一个ThreadA线程,ThreadA使用管道写出流不断写出,ThreadB中注入ThreadA引用,读取ThreadA写出流中的内容,不断打印到控制台。
2、不管哪个线程,run()方法中定义这个线程启动后具体干什么事情,ThreadA的run()方法就是不断写出,ThreadB的run()就是读取ThreadA写出流中的内容,不断打印到控制台。
6.3 面试金手指:管道流
Java管道流定义:实现两个线程之间的数据交互。
1、新建一个ThreadA线程,ThreadA使用管道写出流不断写出,ThreadB中注入ThreadA引用,读取ThreadA写出流中的内容,不断打印到控制台。
2、不管哪个线程,run()方法中定义这个线程启动后具体干什么事情,ThreadA的run()方法就是不断写出,ThreadB的run()就是读取ThreadA写出流中的内容,不断打印到控制台。
七、面试金手指
7.1 顺序流 / 合并流 (定义 + 作用)
合并流定义:JavaIO流——合并流,接收两个输入流作为参数,合并两个输入流或合并流,对外形成一个更大的流,方便客户端操作。
合并流需要注意的点:
1、合并流对应的对象是输入流,是对输入流合并,不是对输出流合并;
2、因为不同输入流有不同对应txt文件,用合并流将两个输入流合并后,可以输入两个文件,注意合并的是两个输入流而不是两个源文件。
3、合并流可以接收合并流作为实际参数,形成多个流的合并,也称合并嵌套。
7.2 对象流:提供一种序列化/反序列化的实现方式
1.1 序列化和反序列化定义:
序列化: 指把堆内存中的Java对象数据,通过某种方式把对象存储到磁盘文件中或者传递给其他网络的节点(在网络上传输). 我们把这个过程称之为序列化.
反序列化:把磁盘文件中的对象数据或者把网络节点上的对象数据,恢复成Java对象的过程.
1.2 为什么要做序列化:
1):在分布式系统中,需要共享的数据的JavaBean对象,都得做序列化,此时需要把对象再网络上传输,此时就得把对象数据转换为二进制形式.以后存储在HttpSession中的对象,都应该实现序列化接口(只有实现序列化接口的类,才能做序列化操作).
2):服务钝化:如果服务发现某些对象好久都没有活动了,此时服务器就会把这些内存中的对象,持久化在本地磁盘文件中(Java对象–>二进制文件). 如果某些对象需要活动的时候,现在内存中去寻找,找到就使用,找不到再去磁盘文件中,反序列化我们得对象数据,恢复成Java对象.
1.3 Java对象流——JavaIO流中实现序列化的方式
使用对象流来完成序列化和反序列化操作:
ObjectOutputStream: 通过writeObject方法做序列化操作的.
ObjectInputStream: 通过readObject方法做反序列化操作的.
ObjectOutputStream ObjectInputStream,提供一种序列化方式,序列化方式有很多,现在互联网大厂常用的是protobuf,最高效的系列化方式
代码1:因为实体类Person没有实现序列化接口Serializable,所以这里程序抛出异常java.io.NotSerializableException。
代码2:实体类Person实现序列化接口后,成功解决了程序异常,一般来说,随着项目的升级,系统的class文件也会升级(增加一个字段/删除一个字段), Java通过serialVersionUID(序列化版本号)来判断字节码是否发生改变.所以我们为实体类Person添加一个序列化版本号。
代码3:给实体类Person加上序列化版本号之后,整个问题正是解决。
JavaIO流——对象流通过writeObject()或readObject()实现序列化和反序列化,在磁盘读写和网络请求中保证数据的正确性。
7.3 与控制台相关:打印流 + 扫描流
打印流定义:
(1)打印到控制台;
(2)解释了System.out.println()底层原理,System.out.println();其实等价于 PrintStream ps = System.out; ps.println(),且见代码1;
扫描流定义:
与打印流对应,解释了控制到输入底层原理,本质上是java.util.Scanner类:扫描器类,表示输入操作,且见代码2。
代码1:打印流为Java提供了一种类似于C/C++的格式化打印,其实只是一种打印的补充格式。因为在Java语言中,System.out.println()通过+号重载可以实现字符串拼接,可以拼接出任何打印格式,所以说System.out.printf()只是提供了另一种打印格式的输出方式。
代码2:扫描类中,hasNextXxx()和nextXxx()两个方法,将字符串内容(也可以是其他内容txt、数组、boolean等)打印出来。
注意:Java BIO流中,打印流用于打印到控制台,扫描流用于读入,甚至可将两个流放在一起写一个demo,可以尝试一下。
7.4 数据流:提供了可以读/写任意数据类型的方法,两个实现类,每个实现类都有writeXxx()和readXxx()方法
数据流定义:提供了可以读/写任意数据类型的方法,两个实现类,每个实现类都有writeXxx()和readXxx()方法。
分别是:
DataOutputStream: 提供了 writeXxx(xxx value)方法.
DataInputStream: 提供了 readXxx()方法.
注意: writeXxx和readXxx必须要对应起来, writeByte写出的数据,此时只能使用readByte读取回来.且见代码1.
数据流的使用:提供了可以读/写任意数据类型的方法,任意数据类型是指8种基本类型(boolean char float double byte short int long),字符串(readChars、readUTF),数组(int数组、byte数组),均有相应的readXxx()和WriteXxx()方法。
7.5 管道流:实现两个线程之间的数据交互
Java管道流定义:实现两个线程之间的数据交互。
1、新建一个ThreadA线程,ThreadA使用管道写出流不断写出,ThreadB中注入ThreadA引用,读取ThreadA写出流中的内容,不断打印到控制台。
2、不管哪个线程,run()方法中定义这个线程启动后具体干什么事情,ThreadA的run()方法就是不断写出,ThreadB的run()就是读取ThreadA写出流中的内容,不断打印到控制台。
八、尾声
IO,对象传输的基石(二),完成了。
天天打码,天天进步!!!