【Java基础|第三十二篇】增强流、缓冲流、标准流、转换流
(九)File流与IO流
3、IO流(增强流部分)
(1)节点流与增强流:
概述:
IO流按照功能划分为节点流和增强流
节点流:
最基本的IO流,直接与数据源或目标进行交互,但缺乏一些高级功能。
它们提供了最底层的读写功能,可以直接读取或写入底层数据源或目标,如文件、网络连接等。
节点流只能提供最基本的读写功能,实际开发中我们很少单独使用它们,也解决复杂IO功能。
上面我们学习的所有流都是节点流:
FileInputStream 和 FileOutputStream :用于读取和写入文件的字节流。
FileReader 和 FileWriter :用于读取和写入文件的字符流
ByteArrayInputStream 和 ByteArrayOutputStream :用于读取和写入字节数组的
增强流:
其在节点流的基础上提供了额外的功能和操作
增强流提供了更高级的操作和便利性,使得 IO 操作更加方便、高效和灵活
增强流不可以独立使用,必须通过装饰器模式包装节点流,可以在节点流上添加缓冲、字符编码转换、对象序列化等功能
常见增强流:缓冲流、标准流、转换流、对象流,数据流,随机访问流等
(2)缓冲流:
<1>缓冲思想:
在 Java 的 I/O 流中,缓冲思想是一种常见的优化技术,用于提高读取和写入数据的效率。它通过在内存中引入缓冲区(Buffer)来减少实际的 I/O 操作次数,从而提高数据传输的效率。
缓冲思想的基本原理是将数据暂时存储在内存中的缓冲区中,然后按照一定的块大小进行读取或写入操作。相比于直接对磁盘或网络进行读写操作,使用缓冲区可以减少频繁的 I/O 操作,从而提高效率。
<2>缓冲流概述:
缓冲流(Buffered Streams)也叫高效流,是一种非常有用的增强流,提供了缓冲功能,可以提高 IO 操作的效率。
缓冲流它们通过在内存中创建一个缓冲区,将数据暂时存储在缓冲区中,然后批量读取或写入数据,减少了频繁的磁盘或网络访问,从而提高了读写的性能。
常见的缓冲流:bufferedInputStream、bufferedOutputStream 缓冲字节输入输出流
bufferedReader,bufferedWriter 缓冲字符输入输出流
内存字节流与缓冲流的区别:
内存字节流中,内存中的字节数组扮演的是数据的目的地,数据源;他解决得是数据的临时存储,主要用于需要短暂存储的数据,不用放在硬盘中,提高了速率,数据随流对象存在。
缓冲流:内存中的缓冲区扮演一个中间角色,作为流的增强器(从输入流拿去一部分数据到缓存区,等缓存区满之后一次性传给程序,或者从输出流拿取一部分数据放在缓存区,等到缓存区满之后一次性传给输入流,减少了输入流与输出流与硬盘之间的频繁操作,提高了传输速率)。
总而言之,内存字节流内存中的字节数组本质是数据容器,替代了硬盘或者是其他外部设备的存储功能。而缓冲流本质是性能优化的中间层,不存储最终的数据,只在程序与外部设备之间增加缓冲层。
<3>缓冲字节流:
①缓冲字节输入流:bufferedInputStream
继承四大父类InputStream
class BufferedInputStream extends FilterInputStream {//省略...//默认缓冲区大小8192字节private static int DEFAULT_BUFFER_SIZE = 8192;//字节数组protected volatile byte buf[];//缓冲区最大字节数private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;//缓冲输入流,又称为包装流,使用时需要传入基本输入字节流对象public BufferedInputStream(InputStream in);//size,代表设置读取缓冲大小public BufferedInputStream(InputStream in, int size); }
主要方法:所继承的是文件字节输入流的read方法,依旧是3种
构造方法:由上图部分源码可知,构造方法有两个,注意参数是字节节点流对象,必须是字节输入流父类对象或者是子类的对象。
②缓冲字节输出流:bufferedOutputStream
继承四大父类:OutputStream
public class BufferedOutputStream extends FilterOutputStream {//省略...protected byte buf[];//使用时需要传入基本输出字节流对象,默认缓冲区大小8192字节public BufferedOutputStream(OutputStream out) {this(out, 8192);}//size,代表设置写入缓冲大小public BufferedOutputStream(OutputStream out, int size); }
主要方法:所继承的是文件字节输出流的write方法,依旧是3种
构造方法:由上图部分源码可知,构造方法有两个,注意参数是字节节点流对象,必须是字节输入流父类对象或者是子类的对象。
案例展示:缓冲流拷贝内容与节点流拷贝内容的比较
public class Test026_Buffered {public static void main(String[] args) throws Exception {//1.创建流对象FileInputStream fis = new FileInputStream("D:\\test\\1.png");FileOutputStream fos = new FileOutputStream("D:\\test\\2.png");//2.借助节点流流 进行 逐行读取long start = System.currentTimeMillis();int data;while((data = fis.read()) != -1) {fos.write(data);}long end = System.currentTimeMillis();System.out.println("拷贝完成,拷贝时长: " + (end - start) + "ms");//3.只需要关闭 最后的增强流对象即可fos.close();fis.close();}
}
//输出结果:文件大小5M左右,注意每次运行结果稍微不同
拷贝完成,拷贝时长: 36410ms
public static void main(String[] args) throws Exception {//1.创建缓冲流FileInputStream fis = new FileInputStream("D:\\test\\1.png");// 注意:缓冲流是增强流,其底层借助节点流实现功能,所以创建时须传入一个节点流对象BufferedInputStream bis = new BufferedInputStream(fis);BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\test\\2.png"));//2.借助缓冲流 进行 逐行读取long start = System.currentTimeMillis();byte[] buff = new byte[1024];int len;while((len = bis.read(buff)) != -1) {bos.write(buff, 0, len);//刷新缓冲流bos.flush();}long end = System.currentTimeMillis();System.out.println("拷贝完成,拷贝时长: " + (end - start) + "ms");//3.只需要关闭 最后的增强流对象即可bos.close();bis.close();
}
//输出结果:文件大小5M左右,注意每次运行结果稍微不同
拷贝完成,拷贝时长: 35ms
从两个的对比中,可以明显看到缓冲流提高了速率。
<4>缓冲字符流:
缓冲字符输入流:bufferedeader
继承四大父类Reader
public class BufferedReader extends Reader {//省略...//基础流private Reader in;//字符数组private char cb[];//默认缓冲区大小private static int defaultCharBufferSize = 8192;//缓冲输入流,又称为包装流,使用时需要传入基本输入字符流对象public BufferedReader(Reader in);//size,代表设置读取缓冲大小public BufferedReader(Reader in, int size);//新增功能:逐行读取数据//如果没有下一行数据了,返回`null`public String readLine() throws IOException; }
构造方法:由上图部分源码可知,构造方法有两个,注意参数是节点流对象,必须是字符输入流对象或者是它的子类对象
主要方法:String readline():一次性读取一整行文本
缓冲字符输入流对象调用,返回所获取到的字符串,无参
Reader父类中有方法:
boolean ready()返回true表示当前流还可以继续读取数据
返回false表示可能要结束或需要等待数据
用于读取数据是检验是否还有数据可读
其他的read方法与文件字符输入流一样。
缓冲字符输出流:bufferedWriter
继承四大父类Writer
public class BufferedWriter extends Writer {//省略...//基础流private Writer out;//字符数组private char cb[];//默认缓冲区大小private static int defaultCharBufferSize = 8192;//缓冲输出流,又称为包装流,使用时需要传入基本输出字符流对象public BufferedWriter(Writer out);//size,代表设置写入缓冲大小public BufferedWriter(Writer out, int size);//新增功能:写入一个换行符,windows、linux等都适用public void newLine() throws IOException; }
构造方法:由上图部分源码可知,构造方法有两个,注意参数是节点流对象,必须是字符输出流对象或者是它的子类对象
主要方法:void newline() 根据当前系统输出一行后插入换行符
其他的写入方法与文件字符输出流一致(Write(String s),write(int c),writer(char[] c));
案例展示:
public class Test026_BufferedChar {public static void main(String[] args) throws Exception {//1.BufferedReader br = new BufferedReader(new FileReader("src/dir/a.txt"));BufferedWriter bw = new BufferedWriter(new FileWriter("src/dir/b.txt"));//2.逐行读取 输出 最后拷贝String line;//读取整行数据 不包含 换行符while((line = br.readLine()) != null) {//输出读取整行数据System.out.println("read: " + line);//将读取的整行数据 写入b.txtbw.write(line);//额外写换行符: 如果后续没有数据了,则不要再写换行符// ready()返回false可理解为:马上要读取到文件尾if(br.ready())bw.newLine();}//3.bw.close();br.close();}
}
(3)标准流:
<1>概述:
标准流(Standard Streams)是指三个预定义的流对象,用于处理标准输入、标准输出和标准错误。这些标准流在 Java 中是自动创建的,无需显式地打开或关闭。
<2>标准输入流:System.in
它是一个字节流(InputStream),用于从标准输入设备(通常是键盘)读取数据。可以使用 Scanner 或 BufferedReader 等类来读取标准输入流的数据。
主要用法:一般借助Scanner与bufferedReader
Scanner sc = new Scanner(System.in);
bufferedReader r = new BufferedReader(System.in);
String a = r.readline(); 一行一行读
默认从控制台写入,如果想要将文件中的写入,可以使用System.setIn(InputStream is)
<3>标准输出流:
它是一个字节流(PrintStream),用于向标准输出设备(通常是控制台)输出数据。可以使用 System.out.println() 或 System.out.print()等方法来输出数据到标准输出流。
默认输出到控制台,如果想输出到文件中,可以使用System.setOut(printStream ps) ;
<4>标准错误流:
用于向标准错误设备(通常是控制台)输出错误信息。与标准输出流相比,标准错误流通常用于输出错误、警告或异常信息。
默认输出到控制台,如果想输出到文件中,可以使用System.setErr(PrintStream ps)
PrintStream:一个增强流
提供了一系列print与println方法,可以输出各种数据类型得值,并自动转化为字符创形式。
特殊之处:构造方法可以直接传路径,可以不传流对象