对于数据的读写操作时,有不同的输入输出对象,Java中是将其当做流的形式来看待。

流(stream)的理解,Stream是从起源(source)到接收(sink)的有序数据

流的分类

  • 数据的输入输出(数据的流向,以程序为中心看待)
    • 输入流
    • 输出流
  • 按照操作数据的单位
    • 字节流:每次读写数据是以一个字节为单位
    • 字符流:每次读写数据是以一个字符(2个字节)为单位
  • 节点流、处理流
    • 节点流:就是直接建立的一种流,没有任何包装的
    • 处理流:在节点流基础上进行包装后的流

字节流

输入:FileInputStream
输出:FileOutputStream

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int read() 
从该输入流读取一个字节的数据,返回-1表示读完了。
int read(byte[] b)
从该输入流读取最多 b.length个字节的数据为字节数组,返回读取的字节个数,返回-1表示读完了。

void write(byte[] b)
将 b.length个字节从指定的字节数组写入此文件输出流。
void write(byte[] b, int off, int len)
将 len字节从位于偏移量 off的指定字节数组写入此文件输出流。
void write(int b)
将指定的字节写入此文件输出流。

void close()
关闭此输入流并释放与流相关联的任何系统资源。

字符流

输入:FileReader
输出:FileWriter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int read() 
读一个字符,返回-1表示读完了。
int read(char[] cbuf)
将字符读入数组,返回读取到的字符个数,返回-1表示读完了。

close()
关闭流,先刷新。
flush()
刷新流。
void write(char[] cbuf)
写入一个字符数组。
void write(char[] cbuf, int off, int len)
写入字符数组的一部分。
void write(int c)
写一个字符
void write(String str)
写一个字符串

缓冲流

缓冲流:可以提高读写的效率
字节缓冲:BufferedInputStream、BufferedOutputStream
字符缓冲:BufferedReader、BufferedWriter

新增方法

1
2
String readLine();
一次读一行(不包含换行符),返回读到的数据,读完了返回null。

转换流

转换流:可以将字节流转换成字符流
输入:InputStreamReader
输出:OutputStreamWriter

构造方法:

1
2
3
4
5
6
7
8
9
InputStreamReader(InputStream in) 
创建一个使用默认字符集的InputStreamReader。
InputStreamReader(InputStream in, Charset cs)
创建一个使用给定字符集的InputStreamReader。

OutputStreamWriter(OutputStream out)
创建一个使用默认字符编码的OutputStreamWriter。
OutputStreamWriter(OutputStream out, Charset cs)
创建一个使用给定字符集的OutputStreamWriter。

打印流

打印流:(只有输出)
字节:PrintStream
字符:PrintWriter

对象流

对象流:可以将java对象进行读写操作,使用对象流可以将数据保存文件、数据库、写入网络在网络上传输
输入:ObjectInputStream
输出:ObjectOutputStream

1、需要类实现Serializable接口,表示当前类可序列化,序列化后对象才可进行读写操作

  • 序列化机制:将一个对象(数据)转换成一个跟平台无关的二进制数据

  • 序列化:将对象转换成二进制数据

  • 反序列化:将对象的二进制数据再转成对象

2、serialVersionUID

1
2
3
4
5
serialVersionUID:当前这个类进行序列化时的一个序列化版本编号(全局唯一)
可以解决一个版本兼容的问题:原先将一个对象存储后,在后面版本中类的结构有发生变化,
这个时候可以通过serialVersionUID进行识别,确保读取时还能够读出来

如果不加:那系统会自动生成一个,若后期类的结构又发生变化,那么又会重新生成,导致读取时两个serialVersionUID不一致,报错

3、序列化其他注意点:

  • transient:可以让属性值不被序列化
  • static:修饰的属性也不会序列化

随机访问流

随机访问流:(读写集合在一起,通过指定的模式来确定读写权限)
RandomAccessFile

构造方法:

1
2
3
// 参数1:file对象,参数2:指定当前流对象的模式
// 模式:"r":表示只读;"rw":表示读写
RandomAccessFile(File file, String mode)

方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
特殊的方法:
// 获取指针的位置
// 指针的作用,指针指向流的某个位置时,那么读写操作将会从这个位置开始
long index = raf.getFilePointer();

// 可以手动指定指针的位置,参数:表示偏移量,在当前位置上偏移多少个字节
raf.seek(5); // 偏移的最大限度可以通过file.length()间接得到

/******************************************************************/
WriteXXX(),readXXX(),进行读写操作时,读写的数据的长度为当前数据类型的长度
例如:
writeInt():写入数据将一次性写入4个字节
readInt():读数据时一次性读4个字节