InputStream 就是Java 标准库提供的最基本的输入流。它位于java.io这个包里。InputStream 不是一个接口,而是一个抽象类,它是所有输入流的超类。
InputStream :字节输入流,进行字节内容的读取
读取方法1:
每次调用read()方法,读取到1个字节,读取至末尾返回-1
读取方法2:批量读取
定义一个数组保存每次读取的结果
利用缓冲区一次性读取多个字节效率会提高
BufferedInputStream 是缓冲输入流。它继承于FilerInputStream。BufferedInputStream的作用是为另一个输入流添加一些功能,例如,提供“缓冲功能”以及支持“mark()标记”和“reset()重置方法”。
BufferedInputStream 本质上是通过一个内部缓冲区数组实现的。例如,在新建某输入流对应的BufferedInputStream后,当我们通过read()读取输入流的数据时,BufferedInputStream会将该输入流的数据分批的填入到缓冲区中。每当缓冲区中的数据被读完后,输入流会再次填充数据缓冲区;如此反复,直到读完。
OutputStream 是Java标准库提供的用于写入操作的基础输入流。和InputStream 类似,OutputStream也是抽象类,它是所有输出流的超类。
BufferedOutputStream 和BufferedInputStream相似都是建立缓冲区。
1.创建FileOutputStream(字节输出流)对象,构造方法中绑定要输出的目标文件对象
2.创建BufferedOutputStream 对象,构造方法中传递FileOutputStream对象,提高FileOutputStream的写入效率
3.使用BufferedOutputStream 对象中的方法write() 方法,把数据写入到内部缓冲区中
4.使用BufferedOutputStream 对象中的flush()方法,把内部缓冲区的数据,刷新到文件中
5.使用BufferedOutputStream 对象中的close()方法,释放资源
如果我们要给 FileInputStream 添加缓冲功能,则可以从 FileInputStream 派生一个子类 BufferedFileInputStream :
public class BufferedFileInputStream extends FileInputSream{ }
如果要给 FileInputStream 添加计算签名的功能,类似的,也可以从 FileInputStream 派生一个子类 DigestFileInputStream :
public class DigestFileInputStream extends FileInputStream{ }
如果要给 FileInputStream 添加加密/解密功能,还是可以从 FileInputStream 派生一个子类 CipherFileInputStream :
public class CipherFileInputStream extends FileInputStream{ }
如果要给 FileInputStream 添加缓冲和签名的功能,那么我们还需要派生子类 BufferedDigestFileInputStream 。如果要给 FileInputStream 添加缓冲和加解密的功能, 则需要派生 BufferedCipherFileInputStream 。
我们发现,给 FileInputStream 添加3种功能,至少需要3个子类。这3种功能的组合,又需要更多的子类,于是就有了装饰器
把资源存储在 classpath 中可以避免文件路径依赖;
Class 对象的 getResourceAsStream() 可以从 classpath 中读取指定资源;
根据 classpath 读取资源时,需要检查返回的 InputStream 是否为 null 。
public static void main(String[] args){
//读取classpath下的properties文件
try(InputStream in = Demo03.class.getResourceAsStream("/config.properties")){
Properties prop = new Properties();
prop.load(in);//通过properties对象加载*.properties文件
System.out.println("key秘钥"+prop.getProperty("key","0000000000"));
}catch(IOException e){
e.printStackTrace();
}
}
ZipInputStream 是一种 FilterInputStream ,它可以直接读取 zip 包的内容:
I n p u t S t r e a m ∣ F i l t e r I n p u t S t r e a m ∣ I n f l a t e r I n p u t S t r e a m ∣ Z i p I n p u t S t r e a m ∣ J a r I n p u t S t r e a m InputStream ^ | FilterInputStream ^ | InflaterInputStream ^ | ZipInputStream ^ | JarInputStream InputStream∣FilterInputStream∣InflaterInputStream∣ZipInputStream∣JarInputStream
ZipInputStream 的基本用法: 首先要创建一个 ZipInputStream ,通常是传入一个 FileInputStream 作为数据 源,然后,循环调用 getNextEntry() ,直到返回 null ,表示 zip 流结束。 一个 ZipEntry 表示一个压缩文件或目录,如果是压缩文件,我们就用 read() 方法不断读取,直到返回 -1
ZipOutputStream 是一种 FilterOutputStream ,它可以直接写入内容到zip包。我们要先创建一个 ZipOutputStream ,通常是包装一个 FileOutputStream ,然后,每写入一个文件前,先调用 putNextEntry() ,然后用 write() 写入 byte[] 数据,写入完毕后调用 closeEntry() 结束这个文件的 打包
ZipInputStream 可以读取 zip 格式的流, ZipOutputStream 可以把多份 数据写入 zip 包;配合 FileInputStream 和 FileOutputStream 就可以读写zip文件
序列化是指把一个 Java 对象变成二进制内容,本质上就是一个 byte[] 数组。 为什么要把Java对象序列化呢?因为序列化后可以把 byte[] 保存到文件中,或 者把 byte[] 通过网络远程传输。这样,就相当于把 Java 对象存储到文件或者通过 网络传输出去了。有序列化,就有反序列化,即把一个二进制内容(也就是 byte[] 数组)变回 Java 对象。有了反序列化,保存到文件中的 byte[] 数组又可以“变回” Java对象,或者从网络上读取 byte[] 并把它“变回”Java对象。
把一个Java对象变为 byte[] 数组,需要使用 ObjectOutputStream 。它负责把一个Java对象写入一个字 节流。 ObjectOutputStream 既可以写入基本类型,如 int , boolean ,也可以写入 String (以UTF8编码),还可以写入实现了 Serializable 接口的 Object 。因为写入 Object 时需要大量的类型信 息,所以写入的内容很大。
import java.io.*;
import java.util.Arrays;
public class Main {
public static void main(String[] args) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try (ObjectOutputStream output = new ObjectOutputStream(buffer)) {
// 写入int:
output.writeInt(12345);
// 写入String:
output.writeUTF("Hello");
// 写入Object:
output.writeObject(Double.valueOf(123.456));
}
System.out.println(Arrays.toString(buffer.toByteArray()));
}
}
和 ObjectOutputStream 相反, ObjectInputStream 负责从一个字节流读取Java对象:
try (ObjectInputStream input = new ObjectInputStream(...)) {
int n = input.readInt();
String s = input.readUTF();
Double d = (Double) input.readObject();
}
可序列化的Java对象必须实现 java.io.Serializable 接口,类似 Serializable 这样的空接口被称为“标记接口”( Marker Interface );
反序列化时不调用构造方法,可设置 serialVersionUID 作为版本号(非必需);
Java的序列化机制仅适用于Java,如果需要与其它语言交换数据,必须使用通用 的序列化方法,例如 JSON 。
通过InputStreamReader转换流将字节流转换为Reader字符流
作为版本号(非必需);
Java的序列化机制仅适用于Java,如果需要与其它语言交换数据,必须使用通用 的序列化方法,例如 JSON 。
[外链图片转存中…(img-orfLkxAu-1706093748833)]
[外链图片转存中…(img-hWWeOS3E-1706093748833)]
通过InputStreamReader转换流将字节流转换为Reader字符流
[外链图片转存中…(img-5pozmc1u-1706093748833)]