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公众号,关注后实时获知布最新的教程和优惠活动,谢谢。


问答区域    
2019-10-09 交作业-关闭流
小企业哒



使用在finally中关闭流的方式,需要注意使用if判断当前流是否存在,如果不存在就没有关闭的必要
////拆分文件
public class HomeWork2 {

	// 练习-拆分文件
	// 找到一个大于100k的文件,
	// 按照50k为单位,拆分成多个子文件,并且以编号作为文件名结束。
	public static void main(String[] args) {
		File file = new File("d:/Dota/BreakUpFile/murasame.txt");
		BreakUpFile(file);
	}

	// 创建拆分文件的方法,传入文件file
	private static void BreakUpFile(File file) {
		// 如果源文件不存在,则报错并退出程序.
		if (!file.exists()) {
			System.err.println("警告:所要拆分的源文件不存在,无法拆分.请检查后重试!");
			return;
		}
		// 如果源文件无内容,则报错并退出程序.
		if (file.length() == 0) {
			System.err.println("警告:所要拆分的源文件无内容,无法拆分,请检查后重试!");
			return;
		}

		// 创建空的字节数组array,长度为传入文件file的长度
		byte[] array = new byte[(int) file.length()];

		// 读取
		// 创建输入流
		FileInputStream fis = null;
		try {
			fis = new FileInputStream(file);
			// 读取文件中的数据并传入字节数组中
			fis.read(array);

		} catch (IOException e) {
			System.err.println("程序发生异常,请检查后重试!");
			e.printStackTrace();
		}
		// 设定拆分文件的大小
		int FileSize = 1024 * 50;
		// 设定拆分文件的数量
		int FileNum;
		// 如果源文件长度刚好为子文件大小的整数倍,则空间刚好全部利用.
		if (array.length % FileSize == 0) {
			FileNum = array.length / FileSize;
		} else {
			// 如果源文件长度不为子文件大小的整数倍,则需要多创建一个文件来存放数据.
			FileNum = array.length / FileSize + 1;
		}
		System.out.printf("文件大小为:%dkb,需要准备%d个50kb的文件.%n", array.length / 1024, FileNum);

		for (int i = 0; i < FileNum; i++) {
			// 将子文件重命名
			String name = new String(file.getName() + "-" + i + ".txt");
			File FileName = new File(file.getParent(), name);
			// 创建标记数组用来存放数据
			byte[] mark = null;

			// 如果当前的文件不是最后一个文件,则每个子文件大小一致
			if (i != FileNum - 1) {
				mark = Arrays.copyOfRange(array, FileSize * i, FileSize * (i + 1));
			} else {
				// 如果当前问就是最后一个文件,则子文件不需要创建多余的空间
				mark = Arrays.copyOfRange(array, FileSize * i, array.length);
			}
			// 写入
			// 创建输出流
			FileOutputStream fos = null;
			try {
				fos = new FileOutputStream(FileName);
				// 将标记数组中的数据写入到子文件中
				fos.write(mark);
				// 关闭输出流
				fos.close();
				System.out.printf("输出子文件%s,其大小为%d字节.%n", FileName, mark.length);
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				// 关闭输入流,输出流
				if (fis != null && fos != null) {
					try {
						fis.close();
						fos.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}
}

////合并文件
public class HomeWork3 {

	// 练习-合并文件
	// 将拆分文件练习中拆分出的文件合并成一个源文件
	public static void main(String[] args) {

		File file = new File("d:\\Dota\\MergeFile\\murasame.txt");
		MergeFile(file);
	}

	// 创建合并文件的方法,传入目标文件file
	private static void MergeFile(File file) {

		File f = new File(file.getParent(), file.getName());
		try (FileOutputStream fos = new FileOutputStream(f)) {
			// 计数器,用来表示第几个子文件
			int num = 0;

			while (true) {
				File FileName = new File(f.getParent(), file.getName() + "-" + (num++) + ".txt");
				// 如果子文件不存在,退出程序
				if (!FileName.exists()) {
					System.out.println("全部子文件均以合并到一个文件中,程序自动退出.");
					break;
				}

				try (FileInputStream fis = new FileInputStream(FileName)) {
					// 创建标记数组,用来存放子文件的数据
					byte[] mark = new byte[(int) FileName.length()];
					// 读取子文件中的数据并传入到标记数组中
					fis.read(mark);
					// 将标记数组中的数据写入到指定文件中
					fos.write(mark);
					System.out.printf("子文件%s已写入到目标文件中.%n", FileName);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			System.out.printf("当前目标文件大小为%d字节.%n", file.length());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

							


1 个答案

Weird-receipt 答案时间:2019-10-22
我吐槽一下,我刚刚把那个关闭流的方式改成finally,然后就发现下一个section说所有的流都实现了AutoCloseable,可以自动关闭流,然后又得改回去 /Facepalm



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





2019-08-30 多个资源的try-with-resources
hugh95
只要在资源间加上“;”就好啦







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




2019-08-19 交作业
2019-08-01 提交作业
2019-07-30 作业
2019-06-12 分分合合
2019-06-03 方法2中为什么声明在try里作用域无法达到finally?
2019-05-31 拆组文件的标准关闭流
2019-05-26 ZZ交作业 关闭流的方式
2018-04-07 flush()的作用
2018-03-22 站长的类后面是不是忘记写 【implements AutoColseable】了???
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群交流: 881555796
提问尽量提供完整的代码,环境描述,越是有利于问题的重现,您的问题越能更快得到解答。
对教程中代码有疑问,请提供是哪个步骤,哪一行有疑问,这样便于快速定位问题,提高问题得到解答的速度
在已经存在的几千个提问里,有相当大的比例,是因为使用了和站长不同版本的开发环境导致的,比如 jdk, eclpise, idea, mysql,tomcat 等等软件的版本不一致。
请使用和站长一样的版本,可以节约自己大量的学习时间。 站长把教学中用的软件版本整理了,都统一放在了这里, 方便大家下载: http://how2j.cn/k/helloworld/helloworld-version/1718.html

上传截图