IO流
目标:
- 基本的字节输入流
InputStream
、字节输出流OutputStream
、字符输入流Reader
、字符输出流Writer
; - 文件的字节输入流
FileInputStream
、字节输出流FileOutputStream
、字符输入流FileReader
、字符输出流FileWriter
; - 缓冲流: 字节缓冲流:
BufferedInputStream
,BufferedOutputStream
;字符缓冲流:BufferedReader
,BufferedWriter
; - 转换流:可以指定字符集,
InputStreamReader(InputStream in, String charsetName)
,OutputStreamWriter(OutputStream in, String charsetName)
Properties
类的store()
方法和load()
方法;- 序列化和反序列化:ObjectOutputStream和ObjectInputStream,对象要实现
java.io.Serializable
接口,不需要可序列化的,使用transient
关键字修饰。 - 打印流
PrintStream
。
1. IO流概述
Java中I/O操作主要是指使用 java.io
包下的内容,进行输入、输出操作。
输入也叫做读取数据,输出也叫做作写出数据。
根据数据的流向分为:输入流和输出流。
格局数据的类型分为:字节流和字符流。
顶级父类:
- 字节输入流:
InputStream
- 字节输出流:
OutputStream
- 字符输入流:
Reader
- 字符输出流:
Writer
2. 字节流
2.1 字节输出流OutputStream
java.io.OutputStream
抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。它定义了字节输出流的基本共性功能方法。
public void close()
:关闭此输出流并释放与此流相关联的任何系统资源。public void flush()
:刷新此输出流并强制任何缓冲的输出字节被写出。public void write(byte[] b)
:将 b.length字节从指定的字节数组写入此输出流。public void write(byte[] b, int off, int len)
:从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。public abstract void write(int b)
:将指定的字节输出流。
2.2 文件字节输出流FileOutputStream
java.io.FileOutputStream extends OutputStream
,文件输出流,将数据写入文件。
- 构造方法:
调用FileOutputStream的构造方法可以按照路径创建文件。
*public FileOutputStream(File file)
:创建文件输出流以写入由指定的 File对象表示的文件。
*public FileOutputStream(String name)
: 创建文件输出流以指定的名称写入文件。
*public FileOutputStream(File file, boolean append)
:第二个参数true
表示追加数据,false
表示清空原有数据。
*public FileOutputStream(String name, boolean append)
- 写入字节方法:
*write(int b)
写入字节;utf-8编码下,中文占3个字节,GBK编码下,中文占2个字节。
*void write(byte[] b)
写入字节数组;
*void write(byte[] b, int off, int len)
写入指定字节数组的指定长度部分。 - 写入换行:
Windows系统里,换行符号是\r\n
linux系统里,换行符号是/n
- 注意:流使用完后要关闭。
2.3 字节输入流InputStream
java.io.InputStream
抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入流的基本共性功能方法。
public void close()
:关闭此输入流并释放与此流相关联的任何系统资源。public abstract int read()
: 从输入流读取数据的下一个字节。public int read(byte[] b)
: 从输入流中读取一些字节数,并将它们存储到字节数组 b中 。
2.4 文件字节输入流FileInputStream
java.io.FileInputStream extends InputStream
,文件输入流,从文件中读取数据。 文件一定要存在才能读取。
-
构造方法:
*public FileInputStream(File file)
:创建文件输入流指向要读取的文件。
*public FileInputStream(String name)
: 创建文件输入流指向要读取的指定路径的文件。
注意:如果该路径或文件不存在,会抛出FileNotFoundException
-
读取字节:
*int read()
从此输入流中读取一个数据字节。每次可以读取一个字节的数据,提升为int类型,读完之后后移一位,读取到文件末尾时返回-1
。
*int read(byte[] b)
,每次读取b的长度个字节到数组中,返回读取到的有效字节个数,读取到末尾时返回-1
。数组起到缓冲作用,长度一般定义为1024的整数倍。 -
复制文件案例:
package cn.itcast;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
public class iodemo {
public static void main(String[] args) throws IOException {
//指定文件源目录
FileInputStream fis = new FileInputStream("D:\\a.jpg");
//指定文件目的目录
FileOutputStream fos = new FileOutputStream("E:\\a.jpg");
// 定义字节数组,作为装字节数据的容器
byte[] bytes = new byte[1024];
// 定义变量,作为有效长度
int len;
long begin = System.currentTimeMillis(); //获取当前时间毫秒值
while ((len = fis.read(bytes)) != -1) {
// 每次读取后,把数组的有效字节部分,写入目的地
fos.write(bytes, 0, len);
}
//关闭资源,先开后关,先关后开
fos.close();
fis.close();
long end = System.currentTimeMillis(); //获取复制完成后时间毫秒值,计算耗时
System.out.println("耗时"+(end-begin)+"毫秒");
}
}
- 注意:流使用完后要关闭。
3. 字符流
遇到中文字符时,字节流可能不会显示完整的字符,因为 一个中文字符可能占用多个字节存储。
字符流,只能操作文本文件,不能操作图片,视频等非文本文件。
3.1 字符输出流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()
关闭此流,但要先刷新它。
3.2 文件字符输出流FileWriter
java.io.FileWriter
类是写出字符到文件的便利类。构造时使用系统默认的字符编码(utf-8)和默认字节缓冲区。继承关系:FileWriter extends OutputStreamWriter extends Writer
- 构造方法:与文件字节输出流一样
调用FileWriter的构造方法可以按照路径创建文件。
*public FileWriter(File file)
:创建文件输出流以写入由指定的 File对象表示的文件。
*public FileWriter(String name)
: 创建文件输出流以指定的名称写入文件。
*public FileWriter(File file, boolean append)
:第二个参数true
表示追加数据,false
表示清空原有数据。
*public FileWriter(String name, boolean append)
- 写入方法:
*write(int b)
: 写入字符
*write(char[] cbuf)
: 写入字符数组;
*write(char[] cbuf, int off, int len)
写入指定字符数组的指定长度部分。
*write(String str)
:写入字符串
*write(String str, int off, int len)
写入指定字符串的指定长度部分。 - 写入换行:
Windows系统里,换行符号是\r\n
linux系统里,换行符号是/n
【注意】 关闭资源时,与FileOutputStream不同。如果不关闭,数据只是保存到缓冲区,并未保存到文件。 - 关闭和刷新方法:
*flush()
:刷新缓冲区,流对象可以继续使用。
*close()
:先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。
3.3 字符输入流Reader
java.io.Reader
抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中。它定义了字符输入流的基本共性功能方法。
public void close()
:关闭此流并释放与此流相关联的任何系统资源。public int read()
: 从输入流读取一个字符。public int read(char[] cbuf)
: 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中 。
3.4 文件字符输入流FileReader
java.io.FileReader
类是读取字符文件的便利类。构造时使用系统默认的字符编码(utf-8)和默认字节缓冲区。继承关系:FileReader extends InputStreamReader extends Reader
-
构造方法:
*public FileReader(File file)
:创建文件输入流指向要读取的文件。
*public FileReader(String name)
: 创建文件输入流指向要读取的指定路径的文件。
注意:如果该路径或文件不存在,会抛出FileNotFoundException
-
读取字符:
*int read()
从此输入流中读取一个数据字符。每次可以读取一个字符的数据,提升为int类型,读完之后后移一位,读取到文件末尾时返回-1
。
*int read(byte[] b)
,每次读取b的长度个字符到数组中,返回读取到的有效字符个数,读取到末尾时返回-1
。数组起到缓冲作用,长度一般定义为1024的整数倍。
4. 属性集Properties
4.1 概述
java.util.Properties
继承自Hashtable
,来表示一个持久的属性集。key和value都是字符串类型,使用时不需要用泛型。可以保存在流中或者从流中加载。
4.2 构造方法
public Properties()
:创建一个空的属性列表。
4.3 基本功能
public Object setProperty(String key, String value)
: 保存一对属性。 相当于put()public String getProperty(String key)
:使用此属性列表中指定的键搜索属性值。相当于get()public Set<String> stringPropertyNames()
:所有键的名称的集合。相当于keySet()
4.4 和流相关的功能store()和load()方法
store()
: 将集合中的临时数据存储,写入到硬盘中。
public void stroe(OutputStream outStream, String comments)
: 从字节输出流中读取键值对。不能写中文。public void stroe(Writer writer,String comments)
: 从字符输出流中读取键值对。
load()
: 从字节输入流中读取键值对。 可以够加载文本中的数据。
public void load(InputStream inStream)
: 从字节输入流中读取键值对。public void load(Reader reader)
: 从字节输入流中读取键值对。
【注意】:文本中的数据,必须是键值对形式,可以使用空格、等号、冒号等符号分隔。
5. 缓冲流
缓冲流,也叫高效流,是对4个基本的FileXxx 流的增强。
缓冲流的基本原理:在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率
按照数据类型分类:
- 字节缓冲流:
BufferedInputStream
,BufferedOutputStream
- 字符缓冲流:
BufferedReader
,BufferedWriter
5.1 字节缓冲流
BufferedInputStream
字节缓冲输入流,继承自InputStream
BufferedOutputStream
字节缓冲输出流,继承自OutputStream
-
构造方法:
*public BufferedInputStream(InputStream in)
:创建一个新的字节缓冲输入流。
*public BufferedInputStream(InputStream in, int size)
:创建一个新的字节缓冲输入流,指定缓冲区大小。*
public BufferedOutputStream(OutputStream out)
: 创建一个新的字节缓冲输出流。
*public BufferedOutputStream(OutputStream out, int size)
:创建一个新的字节缓冲输出流,指定缓冲区大小。 -
读写方法:与普通字节流FileOutputStream,FileInputStream相同。
5.2 字符缓冲流
BufferedReader
字符缓冲输入流,继承自Reader
BufferedWriter
字符缓冲输出流,继承自Writer
-
构造方法:
*public BufferedReader(Reader in)
:创建一个新的字符缓冲输入流。
*public BufferedReader(Reader in, int size)
:创建一个新的字符缓冲输入流, 指定缓冲区大小。*
public BufferedWriter(Writer out)
: 创建一个新的字符缓冲输出流。
*public BufferedWriter(Writer out, int size)
: 创建一个新的字符缓冲输出流, 指定缓冲区大小。 -
基本读写方法: 与普通字符流FileReader、FileWriter相同。
-
特有方法:
BufferedWriter
的特有方法:public void newLine()
: 写一行行分隔符,由系统属性定义符号。
BufferedReader
的特有方法:public String readLine()
: 读一行文字。 返回包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null。
6. 转换流
6.1 字符编码和字符集
- 编码:按照某种规则,将字符存储到计算机中 。
- 解码:将存储在计算机中的二进制数按照 某种规则解析显示出来。
- 字符集 Charset :也叫编码表。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符 号、数字等。常见字符集有ASCII字符集、GBK字符集、Unicode字符集等。
6.2 InputStreamReader类
转换流 java.io.InputStreamReader
,继承自Reader,是从字节流到字符流的桥梁。
可以读取字节,并使用指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集。
- 构造方法:
InputStreamReader(InputStream in)
:创建一个使用默认字符集的字符流。InputStreamReader(InputStream in, String charsetName)
:创建一个指定字符集的字符流。
6.3 OutputStreamWriter类
转换流 java.io.OutputStreamWriter ,继承自Writer,是从字符流到字节流的桥梁。使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集。
7. 序列化
- 对象序列化:
ObjectOutputStream
类用一个字节序列表示一个对象,该字节序列包含该对象的数据 、对象的 类型和对象中存储的属性 等信息。 - 反序列化:
ObjectInputStream
类从字节序列将对象的数据读取回来,重构对象
7.1 ObjectOutputStream
类
java.io.ObjectOutputStream
类,序列化流,继承自OutputStream类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。
- 构造方法:
public ObjectOutputStream(OutputStream out)
: 创建一个指定OutputStream的ObjectOutputStream。 - 序列化操作:
public final void writeObject (Object obj)
: 将指定的对象写入。
【注意】:
1)该类必须实现java.io.Serializable
接口, Serializable 是一个标记接口,不实现此接口会抛出 NotSerializableException 。 该类的所有属性必须是可序列化的。
2)如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用transient
关键字修饰。
3)被static
修饰的变量也不能被序列化。
7.2 ObjectInputStream
类
java.io.ObjectInputStream
类,反序列化流,继承自InputStream类,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。
- 构造方法:
public ObjectInputStream(InputStream in)
: 创建一个指定InputStream的ObjectInputStream。 - 反序列化操作:
public final Object readObject ()
: 读取一个对象。注意返回值类型是Object
类型的对象。
只有能找到这个对象的class文件,才可以进行反序列化操作。否则会抛出ClassNotFoundException 异常。
【注意】:修改类之后,反序列化操作时序列号会和原来的序列号发生冲突,抛出InvalidClassException。解决方法是在类中显式声明其自己的serialVersionUID
,该字段必须是static、final、long 型字段。
8. 打印流
java.io.PrintStream
类,打印流,继承自OutputStream类,能够方便地打印各种数据类型的值,是一种便捷的输出方式;只负责数据的输出,不负责数据的读取;永远不会抛出 IOException。
- 构造方法:
PrintStream(File file)
:输出的目的地是一个文件
PrintStream(OutputStream out)
:输出的目的地是一个字节输出流
PrintStream(String fileName)
:输出的目的地是一个文件路径 - 特有的方法:
void print(任意类型的值);void println(任意类型的值并换行)
System.out
就是标准的输出流PrintStream
类型的,流向是系统规定的,打印在控制台上。System类的静态方法static void setOut(PrintStream out)
可以修改输出的目的地。