流
- 流可以读写很多设备,但是读写操作是规范的
- 流根据方向分为:
*输入流:输入流用于“读”,将数据从外界设备读入程序
*输出流:输出流用于“写”,将数据发送到外界设备 - 流分为:
*节点流(低级流):数据源明确,真实负责读写数据的流
*处理流(高级流):不能独立存在,需要基于其他流进行处理工作,使用高级流的目的是简化读写操作 - 使用文件流与RandomAccessFile读写文件的区别:
*RAF是基于指针进行读写文件数据的,所以可操作指针位置随意读写文件任何位置的数据
*文件流是基于流的形式读写文件数据,所以只能按顺序读写文件数据,且不能返回去重新读写,除非重新创建流进行
字节流
java.io.FileOutputStream
- 文件字节输出流,是一个低级流,负责向文件中写出数据
- 默认创建出来的FOS是覆盖操作,即:当创建好该流针对某文件进行写操作前,流会将该文件所有数据删除,只有本次通过该流写出的数据存于该文件中
- FOS的构造方法支持第二个参数,是一个boolean值,若为true,则是追加写模式,通过该流写出的数据会在该文件末尾被追加
- void write(int d);void write(byte[] d);void write(byte[] d,int offset,int len);
java.io.FileInputStream
- 文件字节输入流,是一个低级流,作用是从文件中读取字节数据
- int read();int read(byte[] b);
- 用文件流复制文件,例:
FileInputStream fis=new FileInputStream("Java.pdf");
FileOutputStream fos=new FileOutputStream("Java_copy.pdf");
int len=0;
byte[] data=new byte[1024*10];
while((len=fis.read(data))!=-1){
fos.write(data,0,len);
}
System.out.println("复制完毕!");
fis.close();
fos.close();
缓冲流
java.io.BufferedInputStream
java.io.BufferedOutputStream
- 使用缓冲流可以提高读写效率进行文件复制工作,例:
FileInputStream fis=new FileInputStream("Java.pdf");
BufferedInputStream bis=new BufferedInputStream(fis);
FileOutputStream fos=new FileOutputStream("Java_copy.pdf");
BufferedOutputStream bos=new BufferedOutputStream(fos);
int d=0;
while((d=bis.read())!=-1){
bos.write(d);
}
System.out.println("复制完毕!");
bis.close();
bos.close(); - 缓冲流读取字节:
*当调用bis.read()方法读取一个字节时,缓冲流会一次性读取若干字节回来,并存入内部维护的一个字节数组中,然后将第一个字节返回,当再次调用该方法读取一个字节时,会直接将字节数组中下一个字节返回,而不是在再去读取数据,直到字节数组所有字节全部返回后才会再一次性读取一组字节回来,所以实际上还是提高了读取数据量减少读取此数提高的读取效率 - void flush();强制将缓冲区内容写出,无论缓冲区是否装满
对象流
java.io.ObjectOutputStream
- 对象输出流,是一个高级流,使用该流可以很方便的将java中的对象转换成一组字节后写出
- OOS提供的写出对象的方法,oos.writeObject(Object obj);该方法将给定的对象转换成一组字节后写出
- 若一个类需要被ObjectOutpitStream写出,则该类必须实现接口Serializable(无抽象方法的空接口)
- 调用writeObject方法后,首先将对象转换成了一组字节,该过程称为:对象序列化。然后将这组字节通过fos写入到文件中的过程称为:持久化
- transient关键字修饰的属性在对象进行序列化时,该属性的值将被忽略
java.io.ObjectInputStream
- 对象输入流,是一个高级流,可以读取一组字节,然后将其还原为对象,读取的字节应当是由ObjectOutputStream将对象转换的
- 将一组字节还原回对象的过程称为:对象反序列化
- 当一个类实现了序列化接口后,应当定义一个常量表示版本号,版本号对对象的反序列化结果产生直接影响,对象在进行序列化时,会将版本号信息也加入到字节中,若我们没有定义版本号,对象输出流会根据当前类的结构生成一个版本号,只要当前类的属性没有发生过结构上的变化,版本号是不变的,但是建议将版本号自行定义出来,以便维护
- 对象输入流ObjectInputStream在反序列化对象时,会检查该对象的版本号与当前类版本号是否一致:若字节中该对象的版本号与当前类版本号一致,反序列化成功,就算类的结构发生了变化也一样可以成功,但是若版本号不一致,那么反序列化时会抛出异常
- 当前类若想序列化,除了当前类需要实现序列化接口外,引用类型的属性都要实现序列化接口,Java API提供的类基本都实现了
- ois.readObject();将字节转换成对象
字符流
java.io.OutputStreamWriter
- 字符流读写数据的单位是字符,但是底层依然是读写字节,所以字符流都是高级流,使用它们可以方便读写文本数据
- OutputStreamWriter,该字符输出流的特点是可以按照指定的字符集写出字符
- 默认创建的字符输出流是按照当前系统默认字符集将写出的字符串转换为对应的字节,也可以按照指定的字符集写出字符串(创建字符流的时候传入想要执行的字符集就可)
java.io.InputStreamReader
- 字符输入流,可以按照指定的字符集读取字符
- 利用文件字节流和字符流可以修改文件的编码