若把输入输出流看作管道

那么 java中 最核心的管道 叫做节点流 有如供暖管道最内层的水管

一般供暖管道都会作保护 在最内层水管外层层包装 这些加了“包装”的流(连同外包装一起!)——就是处理流

又可以类比TCP/IP中的最底层 是数据链路层 直接通过传输设备(如光纤等)传输0101信号 那数据链路层 就是 TCP/IP的“节点流”, 什么微信qq支付宝,就是TCP/IP的“处理流”

节点流、处理流 的异同

按功能不同划分IO流:节点流,处理流。

(1)程序用于直接操作目标设备所对应的类叫节点流。

(2)程序通过一个间接流类去调用节点流类,以达到更加灵活方便地读写各种类型的数据,这个间接流类就是处理流。

这里先以 字节流(字符流本质也是字节流 只是最小传单位不是一个字节 而是几个字节 同理 处理流本质上也是节点流 只是对节点流做了包装) 为例 列出常用的 节点流、处理流:

典型节点流:
FileInputStream
FileOutputStream
典型处理流:
BufferedInputStream
BufferedOutputStream
节点流demo
节点流demo如下(是的 中文是可以作为方法名/变量名的 亲!):
public void 节点流copyFile(String src, String dest) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
File reader = new File(src);
File writer = new File(dest);
fis = new FileInputStream(reader);
fos = new FileOutputStream(writer);
byte[] b = new byte[1024];
int len = 0;
while ((len = fis.read(b)) != -1) {
fos.write(b, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null)
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
if (fos != null)
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Test
public void 节点流CopyFileTest() {
String src = "C:\\Users\\ASUS\\Desktop\\abc.mkv";
String desc = "C:\\Users\\ASUS\\Desktop\\ccc.mkv";
long begin = System.currentTimeMillis();
节点流copyFile(src, desc);
long end = System.currentTimeMillis();
System.out.println("耗时:" + (end - begin) + "ms");
}

程序运行结果:

耗时:1876ms

对比文件,除了创建时间、文件名,其他指标都是一模一样的:

节点流复制视频文件.png

处理流demo

处理流demo如下(注意 先删除刚才复制出来的新文件 ccc.mkv 再运行以下代码):

public void 处理流CopyFileTest(String src, String dest) {
FileInputStream fis = null;
FileOutputStream fos = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
File reader = new File(src);
File writer = new File(dest);
fis = new FileInputStream(reader);
fos = new FileOutputStream(writer);
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
byte[] b = new byte[1024];
int len = 0;
while ((len = bis.read(b)) != -1) {
bos.write(b, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fis != null)
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
if (fos != null)
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Test
public void 处理流CopyFileTest() {
String src = "C:\\Users\\ASUS\\Desktop\\abc.mkv";
String desc = "C:\\Users\\ASUS\\Desktop\\ccc.mkv";
long begin = System.currentTimeMillis();
处理流CopyFileTest(src, desc);
long end = System.currentTimeMillis();
System.out.println("耗时:" + (end - begin) + "ms");
}

程序运行结果:

耗时:297ms

对比文件,除了创建时间、文件名,其他指标都是一模一样的:

处理流复制视频文件.png

处理流做了什么封装?

——主要是一个长度为8192的byte数组(当然,还有其他很多方法):

默认长度为8192.png

new一个8192的数组buf.png

buf数组_本质还是byte_本质是字节!.png

参考以上两demo,大家想想,“裸奔”的节点流,和“精心制作”的处理流,分别对同一个大小为136 MB的视频文件进行复制,分别耗时:1876ms、297ms,可见处理流提高了一个数量级的效率!而在其他业务场景下,处理流的优势会更加凸显!

同时注意到,DEFAULT_BUFFER_SIZE的设置也是有讲究的,太小的话,单次运输的字节数太少,耗时太多,效率太低;太大的话,在堆里new数组耗时、耗空间,复制小文件时,还可能出现“杀猪焉用牛刀”的情况。

因此,DEFAULT_BUFFER_SIZE设置成8192,是综合权衡实际中各种、海量的情况后得出的,这说明java设计者们深谙中庸之道。