how2j.cn


工具版本兼容问题
所有的流,无论是输入流还是输出流,使用完毕之后,都应该关闭。 如果不关闭,会产生对资源占用的浪费。 当量比较大的时候,会影响到业务的正常开展。


本视频是解读性视频,所以希望您已经看过了本知识点的内容,并且编写了相应的代码之后,带着疑问来观看,这样收获才多。 不建议一开始就观看视频



6分37秒
本视频采用html5方式播放,如无法正常播放,请将浏览器升级至最新版本,推荐火狐,chrome,360浏览器 如果装有迅雷,播放视频呈现直接下载状态,请调整 迅雷系统设置-基本设置-启动-监视全部浏览器 (去掉这个选项)



步骤 1 : 在try中关闭   
步骤 2 : 在finally中关闭   
步骤 3 : 使用try()的方式   
步骤 4 : 练习-关闭流   
步骤 5 : 答案-关闭流   

在try的作用域里关闭文件输入流,在前面的示例中都是使用这种方式,这样做有一个弊端;
如果文件不存在,或者读取的时候出现问题而抛出异常,那么就不会执行这一行关闭流的代码,存在巨大的资源占用隐患。 不推荐使用
package stream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; public class TestStream { public static void main(String[] args) { try { File f = new File("d:/lol.txt"); FileInputStream fis = new FileInputStream(f); byte[] all = new byte[(int) f.length()]; fis.read(all); for (byte b : all) { System.out.println(b); } // 在try 里关闭流 fis.close(); } catch (IOException e) { e.printStackTrace(); } } }
步骤 2 :

在finally中关闭

edit
这是标准的关闭流的方式
1. 首先把流的引用声明在try的外面,如果声明在try里面,其作用域无法抵达finally.
2. 在finally关闭之前,要先判断该引用是否为空
3. 关闭的时候,需要再一次进行try catch处理

这是标准的严谨的关闭流的方式,但是看上去很繁琐,所以写不重要的或者测试代码的时候,都会采用上面的有隐患try的方式,因为不麻烦~
package stream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; public class TestStream { public static void main(String[] args) { File f = new File("d:/lol.txt"); FileInputStream fis = null; try { fis = new FileInputStream(f); byte[] all = new byte[(int) f.length()]; fis.read(all); for (byte b : all) { System.out.println(b); } } catch (IOException e) { e.printStackTrace(); } finally { // 在finally 里关闭流 if (null != fis) try { fis.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
步骤 3 :

使用try()的方式

edit
把流定义在try()里,try,catch或者finally结束的时候,会自动关闭
这种编写代码的方式叫做 try-with-resources, 这是从JDK7开始支持的技术

所有的流,都实现了一个接口叫做 AutoCloseable,任何类实现了这个接口,都可以在try()中进行实例化。 并且在try, catch, finally结束的时候自动关闭,回收相关资源。
package stream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; public class TestStream { public static void main(String[] args) { File f = new File("d:/lol.txt"); //把流定义在try()里,try,catch或者finally结束的时候,会自动关闭 try (FileInputStream fis = new FileInputStream(f)) { byte[] all = new byte[(int) f.length()]; fis.read(all); for (byte b : all) { System.out.println(b); } } catch (IOException e) { e.printStackTrace(); } } }
步骤 4 :

练习-关闭流

edit Or  姿势不对,事倍功半! 点击查看做练习的正确姿势
拆分文件 中关闭流的风格,修改成 finally 方式

合并文件 中关闭流的风格,修改成 try() 方式
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
查看本答案会花费3个积分,您目前总共有点积分。查看相同答案不会花费额外积分。 积分增加办法 或者一次性购买JAVA 中级总计0个答案 (总共需要0积分)
查看本答案会花费3个积分,您目前总共有点积分。查看相同答案不会花费额外积分。 积分增加办法 或者一次性购买JAVA 中级总计0个答案 (总共需要0积分)
账号未激活 账号未激活,功能受限。 请点击激活
本视频是解读性视频,所以希望您已经看过了本答案的内容,带着疑问来观看,这样收获才多。 不建议一开始就观看视频

3分36秒 本视频采用html5方式播放,如无法正常播放,请将浏览器升级至最新版本,推荐火狐,chrome,360浏览器 如果装有迅雷,播放视频呈现直接下载状态,请调整 迅雷系统设置-基本设置-启动-监视全部浏览器 (去掉这个选项)


package stream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.Arrays; public class TestStream { public static void main(String[] args) { int eachSize = 100 * 1024; // 100k File srcFile = new File("d:/eclipse.exe"); // splitFile(srcFile, eachSize); } /** * 拆分的思路,先把源文件的所有内容读取到内存中,然后从内存中挨个分到子文件里 * * @param srcFile * 要拆分的源文件 * @param eachSize * 按照这个大小,拆分 */ private static void splitFile(File srcFile, int eachSize) { if (0 == srcFile.length()) throw new RuntimeException("文件长度为0,不可拆分"); byte[] fileContent = new byte[(int) srcFile.length()]; // 为了在finally中关闭,需要声明在try外面 FileInputStream fis = null; try { fis = new FileInputStream(srcFile); fis.read(fileContent); } catch (IOException e) { e.printStackTrace(); } finally { // 在finally中关闭 try { if(null!=fis) fis.close(); } catch (IOException e) { e.printStackTrace(); } } int fileNumber; if (0 == fileContent.length % eachSize) fileNumber = (int) (fileContent.length / eachSize); else fileNumber = (int) (fileContent.length / eachSize) + 1; for (int i = 0; i < fileNumber; i++) { String eachFileName = srcFile.getName() + "-" + i; File eachFile = new File(srcFile.getParent(), eachFileName); byte[] eachContent; if (i != fileNumber - 1) eachContent = Arrays.copyOfRange(fileContent, eachSize * i, eachSize * (i + 1)); else eachContent = Arrays.copyOfRange(fileContent, eachSize * i, fileContent.length); // 为了在finally中关闭,声明在try外面 FileOutputStream fos = null; try { fos = new FileOutputStream(eachFile); fos.write(eachContent); System.out.printf("输出子文件%s,其大小是%,d字节%n", eachFile.getAbsoluteFile(), eachFile.length()); } catch (IOException e) { e.printStackTrace(); } finally { // finally中关闭 try { if(null!=fos) fos.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 合并的思路,就是从eclipse.exe-0开始,读取到一个文件,就开始写出到 eclipse.exe中,直到没有文件可以读 * * @param folder * 需要合并的文件所处于的目录 * @param fileName * 需要合并的文件的名称 * @throws FileNotFoundException */ private static void murgeFile(String folder, String fileName) { File destFile = new File(folder, fileName); // 使用try-with-resource的方式自动关闭流 try (FileOutputStream fos = new FileOutputStream(destFile);) { int index = 0; while (true) { File eachFile = new File(folder, fileName + "-" + index++); if (!eachFile.exists()) break; // 使用try-with-resource的方式自动关闭流 try (FileInputStream fis = new FileInputStream(eachFile);) { byte[] eachContent = new byte[(int) eachFile.length()]; fis.read(eachContent); fos.write(eachContent); fos.flush(); } System.out.printf("把子文件 %s写出到目标文件中%n", eachFile); } } catch (IOException e) { e.printStackTrace(); } System.out.printf("最后目标文件的大小:%,d字节", destFile.length()); } }


HOW2J公众号,关注后实时获知布最新的教程和优惠活动,谢谢。


问答区域    
2018-04-07 flush()的作用
hive
请站长解释一下flush(),百度了一下,大部分解释都看不太懂




3 个答案

xianzhe 答案时间:2018-08-12
强制将缓冲区刷新,将缓冲区数据输出输入,不等缓冲区满,可以理解为下面这个举例中你大号还没拉完,马桶就给你冲掉: ~~~~ flush本意是冲刷,这个方法大概取自它引申义冲马桶的意思,马桶有个池子,你往里面扔东西,会暂时保存在池子里,只有你放水冲下去,东西才会进入下水道。 同理很多流都有一个这样的池子,专业术语叫缓冲区,当你print或者write的时候,会暂时保存在缓冲区,并没有发送出去,这是出于效率考虑的,因为数据不会自己发送过去,必须有其他机制,而且这个很消耗资源,就像马桶你需要很多水,才能冲走,你如果扔一点东西,就冲一次水,那你水费要爆表了,同样如果你写一行文字,或者一个字节,就要马上发送出去,那网络流量,CPU使用率等等都要爆表了,所以一般只有在你真正需要发送否则无法继续的时候,调用flush,将数据发送出去。 ~~~

小原 答案时间:2018-05-22
现在的jdk中close方法中调用了flush方法,大部分情况下应该不用调flush,看一下源码就知道

Jonathon 答案时间:2018-05-19
应该是刷新吧



回答已经提交成功,正在审核。 请于 我的回答 处查看回答记录,谢谢
答案 或者 代码至少填写一项, 如果是自己有问题,请重新提问,否则站长有可能看不到




2018-03-22 站长的类后面是不是忘记写 【implements AutoColseable】了???
hhhh111
步骤3里说:【所有的流,都实现了一个接口叫做 AutoCloseable,任何类实现了这个接口,都可以在try()中进行实例化。】 那么类名后面还要不要显示的实现AutoCloseable这个接口???




1 个答案

秋刀鱼殿下 答案时间:2019-03-06
他已经说了所以得流已经实现了这个接口



回答已经提交成功,正在审核。 请于 我的回答 处查看回答记录,谢谢
答案 或者 代码至少填写一项, 如果是自己有问题,请重新提问,否则站长有可能看不到




2018-02-05 没积分了了,呜呜呜呜,需要购买吗?有没有优惠政策
2018-02-05 我没积分了,需要购买吗?呜呜呜呜呜
2017-12-06 finally方式关闭,请问为什么要加一个if做判断呢?
2017-11-30 这个页面的视频打不开,其他正常
2017-11-26 为什么把null写在前面?
2017-10-24 try中要关闭多个资源怎么办呢?
2016-07-29 问题见图




提问之前请登陆
提问已经提交成功,正在审核。 请于 我的提问 处查看提问记录,谢谢
关于 JAVA 中级-I/O-关闭流的方式 的提问

尽量提供截图代码异常信息,有助于分析和解决问题。 也可进本站QQ群交流: 984886441
提问尽量提供完整的代码,环境描述,越是有利于问题的重现,您的问题越能更快得到解答。
对教程中代码有疑问,请提供是哪个步骤,哪一行有疑问,这样便于快速定位问题,提高问题得到解答的速度
在已经存在的几千个提问里,有相当大的比例,是因为使用了和站长不同版本的开发环境导致的,比如 jdk, eclpise, idea, mysql,tomcat 等等软件的版本不一致。
请使用和站长一样的版本,可以节约自己大量的学习时间。 站长把教学中用的软件版本整理了,都统一放在了这里, 方便大家下载: http://how2j.cn/k/helloworld/helloworld-version/1718.html

上传截图