catch/finally中不应使用 writer.flush()

在开发中遇到了一个问题,关闭流的时候会出现某种莫名其妙的错误。后来一个巧合看到了这个解决方法。

先看问题(知道答案以后,才知道是这里出错了)

FileWriter writer = null;
String file="D:\test.txt";
try{
	writer = new FileWriter(file);
	//某些处理后
	writer.flush();
	writer.close();
}catch(Exception e){
	try {
		if(writer != null){
			writer.flush();
			writer.close();
		}
	} catch (IOException e1) {
		e1.printStackTrace();
	}
}

碰巧看到的那段描述,如下:

方法可能因为checked exception导致清理流或资源失败 

这种方法可能无法清理(关闭,处置)流,数据库对象,或者其他的资源,需要一个明确的清除操作。

一般来说,如果一个方法打开一个流或其他资源,方法应该使用try/ finally块来保证流或资源清理方法返回之前。

这种错误模式在本质上是一样的OS_OPEN_STREAM和ODR_OPEN_DATABASE_RESOURCE错误模式,而是基于一个不同的(希望更好)静态分析技术。见韦默和Necula,查找和防止运行时错误处理错误,对分析技术的描述。 

 

刚开始看到这段话,也是一脸懵逼,我明明在catch中使用了 writer.close() 方法了,为什么还说我没清理流。。。

想了好久才把注意力转移到这个flush()方法上:

FileWriter的flush()方法是从OutputStreamWriter中继承来的,其作用就是清空缓冲区并完成文件写入操作的

 

跟踪flush方法,一直到内部sun.nio.cs.StreamEncoder,找到其实现:

public void flush() throws IOException {
	 synchronized (this.lock) {
	      ensureOpen();
	      implFlush();
	}
}

再跟踪ensureOpen()方法:

private void ensureOpen() throws IOException {
	if (!this.isOpen)
		throw new IOException("Stream closed");
	}
}

终于找到了,原来这里会抛出异常。

我的理解是,同时使用write.flush();  write.close();两个方法。如果flush发生了异常,就会中断程序,把异常抛出来,就不会执行close方法。那么这个流实际上还是没有清理的。但是如果只使用write.close(); 那么会首先执行flush();,即使执行过程中flush发生了异常,也不会抛出来,还是会close的。

所以我最终的解决方案是:在catch/finally中不使用write.flush();,只是用write.close();

FileWriter writer = null;
String file="D:\test.txt";
try{
	writer = new FileWriter(file);
	//某些处理后
	writer.flush();
	writer.close();
}catch(Exception e){
	//nothing
}finally{
	try {
		if(writer != null){
			writer.close();
		}
	} catch (IOException e1) {
		e1.printStackTrace();
	}
}
原文地址:https://www.cnblogs.com/acm-bingzi/p/6400602.html