字节流、字符流、缓存流、转换流、属性集、序列流、打印流
IO 操作
Java中I/O操作主要是指使用java.io
包下的内容,进行输入、输出操作。输入也叫做读取数据,输出也叫做作写出数据。
IO的分类
根据数据的流向分:
- 输入流 :把数据从
其他设备
上读取到内存
中的流。 - 输出流 :把数据从
内存
中写出到其他设备
上的流。
根据数据的类型分
- 字节流 :以字节为单位,读写数据的流。
- 字符流 :以字符为单位,读写数据的流。
IO流相关类
1 | IO流 |
字节流
一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都一个一个的字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。
字节输出流OutputStream
java.io.OutputStream
抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。
public void close()
:关闭此输出流并释放资源。 完成流操作后一定要closepublic void flush()
:刷新此输出流并强制任何缓冲的输出字节被写出。public void write(byte[] b)
:将 b.length字节从指定的字节数组写入此输出流。public void write(byte[] b, int off, int len)
public abstract void write(int b)
:将指定的字节输出流。
FileOutputStream类:文件输出流
public FileOutputStream(File file)
:创建文件输出流, File文件对象public FileOutputStream(String name)
: 创建文件输出流, name文件名- 没有这个文件,则创建,有则清空数据
public FileOutputStream(File file, boolean append)
:public FileOutputStream(String name, boolean append)
:- append为
true
表示追加数据, 为false
同上面两个构造方法
- append为
例子
1 | OutputStream out = new FileOutputStream("./src/Demo11/IO/file.txt"); |
字节输入流InputStream
java.io.InputStream
抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。
public void close()
:关闭此输入流并释放资源。 完成流操作后一定要closepublic abstract int read()
: 从输入流读取数据的下一个字节,没读到返回-1。public int read(byte[] b)
: 从输入流中读取一些字节数,将它们存储到字节数组 b中- 返回读取的字节数, 没有读到内容才会返回-1
FileInputStream类: 文件输入流
FileInputStream(File file)
:FileInputStream(String name)
:- 没有这个文件,会抛出
FileNotFoundException
。
- 没有这个文件,会抛出
例子
1 | InputStream in = new FileInputStream("./src/Demo11/IO/file.txt"); |
字符流
字符流专门用于处理文本文件。使用字节流读取文本文件时,遇到中文字符可能不会显示完整的字符。
字符输入流Reader
java.io.Reader
抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中。
public void close()
:关闭此流并释放资源。public int read()
: 从输入流读取一个字符, 没读到返回-1。public int read(char[] cbuf)
:- 返回读取的字节数, 没有读到内容才会返回-1
FileReader 类:构造时使用系统默认的字符编码和默认字节缓冲区。
FileReader(File file)
: 创建一个新的 FileReader ,给定要读取的File对象。FileReader(String fileName)
: 创建一个新的 FileReader ,给定要读取的文件的名称。
字符输出流Writer
java.io.Writer
抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。
void write(int c)
写入单个字符。void write(char[] cbuf)
写入字符数组。abstract void write(char[] cbuf, int off, int len)
: off开始索引, len写入字符数void write(String str)
写入字符串。void write(String str, int off, int len)
写入字符串的某一部分,off字符串的开始索引,len写的字符个数。void flush()
刷新该流的缓冲。void close()
关闭此流,但要先刷新它。
FileWriter类: 构造时使用系统默认的字符编码和默认字节缓冲区。
FileWriter(File file)
: 创建一个新的 FileWriter,给定要读取的File对象。FileWriter(String fileName)
: 创建一个新的 FileWriter,给定要读取的文件的名称。
关闭/刷新缓冲区
flush
:刷新缓冲区,流对象可以继续使用。- 缓冲区满了,无需调用flush方法便会自动刷新。
- 但没有刷新缓冲区,无法写入字符到文件中。
close
:先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了
属性集Properties
java.util.Properties
继承于Hashtable
,来表示一个持久的属性集, 可保存在流中或从流中加载。它使用键值结构存储数据,且键和值都是字符串类型。
public Properties()
:创建一个空的属性列表。public Object setProperty(String key, String value)
: 保存一对属性。public String getProperty(String key)
:使用此属性列表中指定的键搜索属性值。public Set<String> stringPropertyNames()
:所有键的名称的集合。
与流相关的方法
void store(OutputStream out, String comments)
将此 Properties 表中的属性列表(键和元素对)写入输出流。void store(Writer writer, String comments)
将此 Properties 表中的属性列表(键和元素对)写入输出字符。public void load(InputStream inStream)
: 从字节输入流中读取键值对。void load(Reader reader)
从输入字符流中读取属性列表(键和元素对)。
例子
1 | FileWriter fw = new FileWriter("prop.file"); |
缓冲流
缓冲流,也叫高效流,是对4个基本的FileXxx
流的增强,所以也是4个流。
缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。
public BufferedInputStream(InputStream in)
:创建一个 新的缓冲输入流。public BufferedOutputStream(OutputStream out)
: 创建一个新的缓冲输出流。- 字符缓冲流的基本方法与普通字符流调用方式一致, 需要注意的是缓存流的close方法会关闭传入普通字符流
转换流
InputStreamReader类
转换流java.io.InputStreamReader
,是Reader的子类,是从字节流到字符流的桥梁。
它读取字节,并使用指定的字符集将其解码为字符。
InputStreamReader(InputStream in)
: 创建一个使用默认字符集的字符流。InputStreamReader(InputStream in, String charsetName)
: 创建一个指定字符集的字符流。
OutputStreamWriter类
转换流java.io.OutputStreamWriter
,是Writer的子类,是从字符流到字节流的桥梁。
使用指定的字符集将字符编码为字节。
OutputStreamWriter(OutputStream in)
: 创建一个使用默认字符集的字符流。OutputStreamWriter(OutputStream in, String charsetName)
: 创建一个指定字符集的字符流。
序列化
Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据
、对象的类型
和对象中存储的属性
等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。
该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。
ObjectOutputStream类
java.io.ObjectOutputStream
类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。
public ObjectOutputStream(OutputStream out)
public final void writeObject(Object obj)
一个对象要想序列化,必须满足两个条件:
- 该类必须实现
java.io.Serializable
接口Serializable
是一个标记接口- 对没有实现该接口的类,进行序列化反序列化会抛出
NotSerializableException
。
- 该类的所有属性必须是可序列化的。
- 如果有一个属性不需要可序列化的,则该属性必须使用
transient
关键字注明是瞬态的。
- 如果有一个属性不需要可序列化的,则该属性必须使用
ObjectInputStream类
ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。
public ObjectInputStream(InputStream in)
: 创建一个指定InputStream的ObjectInputStream。public final Object readObject ()
: 读取一个对象。
反序列化前提:
- 要能找到这个对象的class文件
- 找不到该类的class文件,则抛出一个
ClassNotFoundException
异常。
- 找不到该类的class文件,则抛出一个
- 序列化之后,class文件不能发生改变
- 发生改变,则会抛出一个
InvalidClassException
异常。 Serializable
接口给需要序列化的类,提供了一个版本序列号serialVersionUID
用于验证序列化的对象和对应类是否版本匹配。我们可以给它一个固定值,这样就不受该序列号的影响了
- 发生改变,则会抛出一个
例子:序列化集合
1 | public static void main(String[] args) throws Exception { |
打印流
平时我们在控制台打印输出,是调用print
方法和println
方法完成的,这两个方法都来自于java.io.PrintStream
类,该类能够方便地打印各种数据类型的值,是一种便捷的输出方式。
System.out
就是PrintStream
类型的,只不过它的流向是系统规定的,打印在控制台上。
public PrintStream(String fileName)
: 使用指定的文件名创建一个新的打印流。
例子:改变打印流
1 | System.setOut(new PrintStream("out.txt")); |