2.3关闭输出流
当你完成了一个流,你应当关闭它。这样就让操作系统释放了与流相关的资源。精确的来说,这些资源取决于你的平台随着你的流的类型而变化。但是很多系统都只有有限的资源。举一个例子,在很多个人电脑上的操作系统,不能同时打开几百个文件。多用户操作系统有很大的限制空间,但限制尽管如此。
为了关闭一个流,调用它的 close() 方法:
public void close( ) throws IOException
举一个例子,再次假设 out 是一个 OutputStream, 调用 out.close() 关闭这个流然后释放一些与这个流相关联的潜在资源比如文件句柄或者网络端口。一旦你关闭了一个输出流,你大概不能够写任何其它的东西在那个流上面了。你试图去这样做但是会抛出一个 IOException, 尽管有一些类不会发生这种情况。
此外,Sysout.out 是一个局部异常因为作为一个 PringStream, 所有抛出的异常都被吃掉了。一旦你关闭
System.out, 你不能去写它 。试着这样去做不会抛出任何异常;但是,你的输出不会出现在控制台上。
不是所有的流都需要被关闭。比如字节数组输出流没有必要被关闭。但是,当你在使用那些与文件和网络连接有关系的流时它们需要被关闭。举一个例子,假如你打开一个文件去写却在完成的时候忘记关闭它,这样其它的进程也许会在读写那个文件时发生阻塞。通常,文件关闭因该这样:
try{
OutputStream out = new FileOutputStream("numbers.dat");
//Write to the stream...
out.close();
}
catch(IOException ex){
System.err.println(ex);
}
但是,这个代码片段有一个潜在的漏洞。假如一个IOException在写的时候被抛出,这个流就不会被关闭。比较可靠的做法是关闭这个流在finally语句块中无论异常是否会抛出。这样做你需要声明OutputStream 值在try语句块的外面。比如:
//Initialize this to null to keep the compiler from complaining
//about uninitialized variables
OutputStream out = null;
try {
out = new FileOutStream("numbers.dat');
//Write to the stream...
}
catch (IOException ex) {
System.err.println(ex);
}
finally{
if(out != null) {
try {
out.close();
}
catch (IOException ex){
System.err.println(ex);
}
}
}
Variable scope and nested try-catch-finally blocks make this a little uglier, yet it's quite a bit safer. The code can be a little cleaner if you have the option of propagating any IOExceptions thrown rather than catching them; that is, if the method that contains this code is declared to throw IOException. In that case, a typical call to close( ) works like this:
值范围和嵌套的try-catch-finall语句块使这个有一点奇怪,但是它确实安全了很多。如果你有选择去抛出一个IOExceptions 而不是去捕捉它们,这个代码能够更简洁。假如一个方法被声明用来抛出异常。在那种情况下,一个典型的调用close()是这样工作的:
// Initialize this to null to keep the compiler from complaining
// about uninitialized variables
OutputStream out == null;
try {
out = new FileOutputStream("numbers.dat");
// Write to the stream...
}
finally {
if (out != null) out.close( );
}
2.3.1 Closeable 接口
Java 5 加入了一个 Closeable 的接口 , OutputStream实现了它
package java.io;
public interface Closeable {
void close( ) throws IOException;
}
InputStream, Channel, Formatter,还有其它各种各样的实现了这个接口就能被关闭。个别的,我没有找出用于额外接口的用例,但是你想要写一个接受能够关闭的参数的方法或者其它类似的。
2.4.刷新输出流
许多输出流缓存用来提高性能。不是发送每个字节到写的目的地,字节在缓存中增加从一些字节到数千字节。当缓存填满了,所有的数据被一次发送。这个 flush() 方法强制写数据无论缓存是否已经满了
public void flush() throws IOException
这和操作系统或者硬件执行的缓存是不同的。调用flush(),缓存不会被清除.(这个在FileDescriptor类中sync()方法,会在17章讨论,有时能够清空这些缓存。)
假如你使用一个流一小段时间,你不需要明确的刷新它。当流关闭的时候它将会被自动的刷新。当程序退出或者close()方法被调用时这个将会发生。你明确的刷新一个输出流只有当你当你确认数据在流结束之前已经被发送了。举一个例子,一个程序定期通过网络发送大量的数据应当刷新在每次大量数据被写入流中时 。
当你在debug一个崩溃的程序时 。当他们的缓存被填满时所有的的流是自动刷新的,当一个程序终止的时候所有的流应当会被刷新。当一个程序在非正常情况下总之,缓存也许不会被刷新。在这种情况下,除非在每次写操作后调用flush(), 你不能确定数据输出表明程序崩溃的位置.事实上,这个程序已经继续运行了一些时间在崩溃之前。
System.out,System.err,和一些其它打印流在调用println()自动刷新然后一个新的换行符('\n')出现在被打印的字符中。在PrintStream 构造器中设置能够或者不能够自动刷新。
2.4.1 Flushable 接口
Java 5 添加了一个 Flushable 接口 , OutputStream 类实现了它
package java.io;
public interface Flushable {
void flush( ) throws IOException;
}
2.5 子类化输出流
OutputStream 是一个抽象类主要描述了一些与OutputStream相关的操作。特殊的的子类知道怎样去写字节到一个特殊的目的地。一个实例,一个 FileOutputStream 使用自己的代码去写数据。一个 ByteArrayOutputStream 使用纯Java 去写一个输出在扩展的字节数组中。