高级流:建立在低级流的基础上的。
IO流及作用
- 字节流: 以一个byte(8bit)为基本单位传输的流;适合处理非文本数据
- 字符流: 以一个char(两个字节:16bit)为基本单位传输的;适合处理文本数据
- 节点流: 直接作用在文件上的流 (低级流)
- 处理流: 作用在已有节点流处理之上的(高级流)
流分类
缓冲流:缓冲流是一对高级流,不能独立存在,作用是提高读写数据的效率.
缓冲流内部有一个字节数组,.缓冲流读写数据时一定是将数据的读写方式转换为块读写来保证读写效率.
* 高级流好比家里常见的对水做加工的设备,比如"净水器","热水器"。
* 有了它们我们就不必再自己对水进行加工了。
原理:在创建流对象时,会创建一个内置的默认大小的缓冲区数组[默认长度是8K],通过缓冲区读写,减少系统IO次数,从而提高读写的效率
流的连接:实际开发中我们经常会串联一组高级流最终连接到低级流上,在读写操作时以流水线式的加工,完成复杂IO操作。这个过程也称为"流的连接"。
BufferedOutputStream(缓冲输出流) 和 BufferedInputStream(缓冲输入流)
//通过缓冲流写出的数据会被临时存入缓冲流内部的字节数组,直到数组存满数据才会真实写出一次
FileInputStream fis = new FileInputStream("ppt.pptx");//文件输入流
BufferedInputStream bis = new BufferedInputStream(fis);//缓冲输入流
FileOutputStream fos = new FileOutputStream("ppt_cp.pptx"); //文件输出出流
BufferedOutputStream bos = new BufferedOutputStream(fos);//缓冲输出流
int d;
long start = System.currentTimeMillis();
while((d = bis.read())!=-1){//使用缓冲流读取字节
bos.write(d);//使用缓冲流写出字节
}
long end = System.currentTimeMillis();
System.out.println("耗时:" (end-start) "ms");
/*
缓冲流的flush方法用于强制将缓冲区中已经缓存的数据一次性写出。
注:该方法实际上实在字节输出流的超类OutputStream上定义的,并非只有缓冲
输出流有这个方法。但是实际上只有缓冲输出流的该方法有实际意义,其他的流实现
该方法的目的仅仅是为了在流连接过程中传递flush动作给缓冲输出流。
*/
bos.flush();//冲
bis.close();//关闭流时只需要关闭高级流即可,它会自动关闭它连接的流
bos.close();
对象流:高级流,在流连接中的作用是进行对象的序列化与反序列化。
- 对象序列化:将一个java对象按照其结构转换为一组字节的过程
- 对象反序列化:将一组字节还原为java对象(前提是这组字节是一个对象序列化得到的字节)
对象流理解图
ObjectOutputStream(序列化) 和 ObjectInputStream(反序列化)
public class Person implements Serializable {
/*
实现序列化接口后最好主动定义序列化版本号这个常量。
这样一来对象序列化时就不会根据类的结构生成一个版本号,而是使用该固定值。
那么反序列化时,只要还原的对象和当前类的版本号一致就可以进行还原。
*/
public static final long serialVersionUID = 1L;
private String name; //姓名
private int age; //年龄
private String gender; //性别
/*
当一个属性被关键字transient修饰后,那么当进行对象序列化时,该属性值会被忽略
忽略不必要的属性可以达到对象瘦身的目的,减少资源开销。
*/
private transient String[] otherInfo; //其他信息
public Person(){}
public Person(String name, int age, String gender, String[] otherInfo) {
this.name = name;
this.age = age;
this.gender = gender;
this.otherInfo = otherInfo;
}
}
//
String name = "太阳系";
int age = 500;
String gender = "其他";
String[] otherInfo = {"恒星系","银河系","地球隔壁","发光球体"};
Person p = new Person(name,age,gender,otherInfo);
System.out.println(p);
FileOutputStream fos = new FileOutputStream("person.obj");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(p);
System.out.println("写出完毕!");
oos.close();
//从person.obj文件中将对象反序列化回来
FileInputStream fis = new FileInputStream("person.obj");
ObjectInputStream ois = new ObjectInputStream(fis);
/*
Object readObject()
该方法会进行对象的反序列化,如果对象流通过其连接的流读取的字节分析并非
是一个java对象时,会抛出异常:ClassNotFoundException
*/
Person p = (Person)ois.readObject();
System.out.println(p);
- 需要进行序列化的类必须实现接口:java.io.Serializable
- 实现序列化接口后最好主动定义序列化版本号这个常量。
- 这样一来对象序列化时就不会根据类的结构生成一个版本号,而是使用该固定值。
- 那么反序列化时,只要还原的对象和当前类的版本号一致就可以进行还原。
- transient关键字可以修饰属性,用于在进行对象序列化时忽略不必要的属性,达到对象瘦身的目的
字符流
- java将流按照读写单位划分为字节流与字符流.
- java.io.InputStream和OutputStream是所有字节流的超类
- 而java.io.Reader和Writer则是所有字符流的超类,它们是平级关系.
- Reader和Writer是两个抽象类,里面规定了所有字符流都必须具备的读写字符的相关方法.
- 字符流最小读写单位为字符(char),但是底层实际还是读写字节,只是字符与字节的转换工作由字符流完成.
转换流
java.io.InputStreamReader和OutputStreamWriter
意义:实际开发中我们还有功能更好用的字符高级流.但是其他的字符高级流都有一个共通点:不能直接连接在字节流上.而实际操作设备的流都是低级流同时也都是字节流.因此不能直接在流连接中串联起来.转换流是一对可以连接在字节流上的字符流,其他的高级字符流可以连接在转换流上.在流连接中起到"转换器"的作用(负责字符与字节的实际转换)。
OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集(gbk)。
//向文件osw.txt中写入文字
FileOutputStream fos = new FileOutputStream("osw.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos,"UTF-8");
osw.write("我可以接受你的所有,所有小脾气.");
osw.write("我可以带你去吃很多,很多好东西.");
osw.flush(); //冲
System.out.println("写出完毕!");
osw.close();
InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
//将osw.txt文件中的所有文字读取回来.
FileInputStream fis = new FileInputStream("osw.txt");
InputStreamReader isr = new InputStreamReader(fis,"UTF-8");
/*
字符流读一个字符的read方法定义:
int read()
读取一个字符,返回的int值实际上表示的是一个char(低16位有效).如果返回的
int值表示的是-1则说明EOF
*/
//测试读取文件中第一个字
// int d = isr.read();
// char c = (char)d;
// System.out.println(c);
//循环将文件所有字符读取回来
int d;
while((d = isr.read()) != -1){
System.out.print((char)d);
}
isr.close();
缓冲字符流
缓冲字符流是一对高级流(BufferedReader和BufferedWriter),在流连接中的作用是提高读写文本数据的效率,并且可以按行读写字符串
BufferedReader 从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取, 可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了,默认缓冲的大小是8K,如果默认缓冲区的大小不足以满足需求时可以自定义缓冲的大小。
//将当前源代码输出到控制台上
FileInputStream fis = new FileInputStream("./src/io/BRDemo.java");
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
/*
BufferedReader提供了一个读取一行字符串的方法:
String readLine()
该方法会连续读取若干字符,当遇到换行符停止,然后将换行符之前的内容以一个
字符串形式返回。
注:这是内存操作,因为第一次调用readLine时,缓冲流会将数据先一次性读取到
内部的char数组中(8K的字符),然后返回内部的一行字符串
如果流读取到了末尾,会返回null。
*/
String line;
while((line = br.readLine())!=null) {
System.out.println(line);
}
br.close();
BufferedWriter: 将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。 可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值(8k)就足够大了
//创建文件流时可以使用追加模式
FileOutputStream fos = new FileOutputStream("pw2.txt",true);
//创建转换流时指定字符集
OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
BufferedWriter bw = new BufferedWriter(osw);
//----------------bw.write(line);
//----------------bw.newLine();
/*
PrintWriter提供的构造方法中如果第一个参数是一个流,那么就可以再传入
一个boolean值的参数用于指定是否打开自动行刷新功能(默认是false不打开)
当该值为true时就打开了自动行刷新功能。
每当我们调用println方法写出一行字符串后就会自动flush一次。
*/
PrintWriter pw = new PrintWriter(bw,true);
Scanner scanner = new Scanner(System.in);
while(true) {
String line = scanner.nextLine();
if("exit".equalsIgnoreCase(line)){
// if("exit".equals(line)){
break;
}
pw.println(line);
}
System.out.println("再见!");
pw.close();
实际开发中缓冲字符输出流我们更常用的是PrintWriter,具有自动行刷新功能的缓冲字符输出流,其内部总是连接BufferedWriter作为缓冲加速使用
打印输出流内部结构
//向文件中写入字符串
PrintWriter pw = new PrintWriter("pw.txt","UTF-8");
pw.println("我看过沙漠下暴雨");
pw.println("看过大海亲吻鲨鱼");
pw.println("看过黄昏追逐黎明");
pw.println("没看过你");
System.out.println("写出完毕!");
pw.close();
//做个小功能,终端输入的内容,写入文件中
//文件字节输出流(是一个低级流),向文件中写入字节数据
FileOutputStream fos = new FileOutputStream("pw2.txt",true);
//转换输出流(是一个高级流,且是一个字符流)。1:衔接字符与字节流 2:将写出的字符转换为字节
OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
//缓冲输出流(是一个高级流,且是一个字符流)。块写文本数据加速
BufferedWriter bw = new BufferedWriter(osw);
//具有自动行刷新的缓冲字符输出流
/*
PrintWriter提供的构造器中,当第一个参数为一个流时,就支持再传入一个boolean
型的参数表示是否自动行刷新。当该值为true时则打开了自动行刷新功能。这意味着
每当我们调用println方法后会自动flush一次。
*/
PrintWriter pw = new PrintWriter(bw, true);
//完成简易记事本。控制台输入的每行字符串都按行写入文件。单独输入exit时退出。
Scanner scanner = new Scanner(System.in);
while(true){
String line = scanner.nextLine();
if("exit".equalsIgnoreCase(line)){
break;
}
pw.println(line);
}
pw.close();
学习记录,如有侵权请联系删除。