java IO相关API探索之Closeable和InputStream接口
2014-12-01 22:01
375 查看
<span style="font-family:Comic Sans MS;font-size:18px;">import java.io.IOException; /** * A {@code Closeable} is a source or destination of data that can be closed. * The close method is invoked to release resources that the object is * holding (such as open files). * * @since 1.5 */ public interface Closeable extends AutoCloseable { /** * Closes this stream and releases any system resources associated * with it. If the stream is already closed then invoking this * method has no effect. * * <p> As noted in {@link AutoCloseable#close()}, cases where the * close may fail require careful attention. It is strongly advised * to relinquish the underlying resources and to internally * <em>mark</em> the {@code Closeable} as closed, prior to throwing * the {@code IOException}. * * @throws IOException if an I/O error occurs */ public void close() throws IOException; }</span>
<span style="font-family:Comic Sans MS;font-size:18px;">接口Closeable继承自AutoCloseable,同时重写了关于 close关闭流的方法。Closeable 是一个能够被关闭的数据源,close方法被调用区释放对象持有的资源例如打开的文件。</span>
关闭stream流和与之相关的资源,如果流已经关闭了,那么再次调用这个方法是没有影响的。与AutoCloseable中的close方法一样,如果关闭操作失败,那么就要格外注意了。
当IO异常发生时该方法会抛出IOExce异常
上面主要是关于Closeable的介绍,而InputStream则是Closeable的一个实现,而InputStream是一个抽象类,所谓抽象类就是该类不能被实例化,只能实例化它的非抽象子类,我看的是jdk1.8的实现。
public abstract class InputStream implements Closeable
MAX_SKIP_BUFFER_SIZE is used to determine the maximum buffer size to
use when skipping. private static final int MAX_SKIP_BUFFER_SIZE = 2048;
类中定义了一个static final类型的变量,用来指定InputStream流一次能够跳过的字节的最大值(忽略字节),后面的一个方法skip会用到这个常量
<span style="font-family:Comic Sans MS;font-size:18px;">public abstract int read() throws IOException;</span>这个read方法待实现,主要是从流中读取一个字节作为输出,Reads the next byte of data from the input stream,因为0-255能够表示所有的字节,所以如果read方法返回-1,则说明这个流已经到了末尾。则不再读取即可.在while中直接break就OK了。
<span style="font-family:Comic Sans MS;font-size:18px;">public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}</span>
read(byte b[])方法读取流中的b.length个字节到字节数组b[]中。返回值表示读取到字节数组中的字节数。下面我们看一下关于read(b, 0, b.length)方法怎么实现的。
<span style="font-family:Comic Sans MS;font-size:18px;">public int read(byte b[], int off, int len) throws IOException { if (b == null) { throw new NullPointerException(); } else if (off < 0 || len < 0 || len > b.length - off) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } int c = read(); if (c == -1) { return -1; } b[off] = (byte)c; int i = 1; try { for (; i < len ; i++) { c = read(); if (c == -1) { break; } b[off + i] = (byte)c; } } catch (IOException ee) { } return i; }</span>
(off表示开始位置,len表示读取流的最长字节)如果b字节数组为null的话,则会抛出空指针异常,如果开始位置off 小于0或者len小于0或者len > b.length - off(表示从开头off + 要读取的字节长度 len) 大于字节数组的length,则抛出数组越界异常。
如果len == 0,那么则直接返回0,表示读入到字节数组中的字节数为0;向后读取一个字节,如果返回为-1,则表示已经到达流的末尾,返回-1即可。b[off] = (byte)c;从这句代码就可以知道read(b, off, len)是把文件流读入到b字节数组中,读入数组中的位置从off索引开始,并且最长能够读取的就是填到b的末尾了,但是由于是从字节的off索引开始填充的,所以最长只能够读取b.length
- off个字节。后面一个for循环,一个字节一个字节的读入到字节数组中off+i索引的位置。如果读到-1,那么跳出循环,返回读入到数组中的字节个数。
下面这个方法就是用到了最开始定义的最长能够跳过的字节数
<span style="font-family:Comic Sans MS;font-size:18px;">public long skip(long n) throws IOException { long remaining = n; int nr; if (n <= 0) { return 0; } int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining); byte[] skipBuffer = new byte[size]; while (remaining > 0) { nr = read(skipBuffer, 0, (int)Math.min(size, remaining)); if (nr < 0) { break; } remaining -= nr; } return n - remaining; }</span>
跳过Math.min(MAX_SKIP_BUFFER_SIZE, remaining),这么长的字节,所谓的跳过,就是把这么多字节读入到另外一个不处理的字节数组中,然后函数结束的时候会自动释放,这样就跳过了一些流中的字节。比如要跳过3000字节,那么在调用Math.min方法的时候就会设置size=2048,然后调用read方法把2048个字节读入到skipBuffer字节数组中,假设文件流中只剩下了1000个字节,那么根据上面的方法介绍,则第一次进入while循环时,nr=1000,remaining=3000-1000=2000,因为n=3000,所以该函数返回3000-2000=1000,所以该函数返回的数据是跳过的字节数。
<span style="font-family:Comic Sans MS;font-size:18px;">public int available() throws IOException { return 0; }</span>
代码中是这么解释返回值的:返回一个可能被读取的流中的字节数或者能够跳过的流中字节数,该方法要其子类来实现,其实就是返回流中的字节数.
<span style="font-family:Comic Sans MS;font-size:18px;">public void close() throws IOException {}</span>
这个方法就不用多说了,关闭文件流操作,不过具体实现要待子类中实现了。
publicsynchronizedvoid mark(intreadlimit) {}
同步操作,mark就像书签一样,在这个BufferedReader对应的buffer里作个标记,以后再调用reset时就可以再回到这个mark过的地方。mark方法有个参数,通过这个整型参数,你告诉系统,希望在读出这么多个字符之前,这个mark保持有效。读过这么多字符之后,系统可以使mark不再有效,而你不能觉得奇怪或怪罪它。这跟buffer有关,如果你需要很长的距离,那么系统就必须分配很大的buffer来保持你的mark。
//reader is a BufferedReader
reader.mark(50);//要求在50个字符之内,这个mark应该保持有效,系统会保证buffer至少可以存储50个字符
int a = reader.read();//读了一个字符
int b = reader.read();//又读了一个字符
//做了某些处理,发现需要再读一次
reader.reset();
reader.read();//读到的字符和a相同
reader.read();//读到的字符和b相同
对应的使用reset则使得文件流指针又指向了原来mark的位置,读取相同数据
<span style="font-family:Comic Sans MS;font-size:18px;">public synchronized void reset() throws IOException { throw new IOException("mark/reset not supported"); }</span>
该方法待子类实现。这里只抛出了不支持mark或者reset方法。
<span style="font-family:Comic Sans MS;font-size:18px;">public boolean markSupported() { return false; }</span>
测试这个文件流是否支持mark以及reset方法。
下面是测试代码:
<span style="font-family:Comic Sans MS;">// TODO Auto-generated method stub
//文件中的内容为:helloworld
File file = new File("/users/terrylmay/desktop/test.txt");
FileInputStream fis = new FileInputStream(file);
BufferedInputStream br = new BufferedInputStream(fis);
//br.skip(2);跳过两个字节,那么流中就只剩下了lloworld
br.skip(2);
//设置在读取的5个字节内标识有效,并且标记当前位置
br.mark(5);
//读取两个字节a = 'l' b='l'
int a = br.read();
int b = br.read();
//打印
System.out.println(""+(char)a+(char)b);
//使得复位
br.reset();
//再次读取流中的字节
a = br.read();
b = br.read();
//打印
System.out.println(""+(char)a+(char)b);
//返回流中的剩余字节
int length = br.available();
System.out.println(length);</span>
打印结果为:
ll
ll
6
相关文章推荐
- java IO相关API探索之 AutoCloseable接口
- java IO相关API探索之Buffer类
- java IO相关API探索之FileInputStream类
- java IO相关API探索之ByteBuffer
- java IO相关API探索之FileChannel类
- Android 网络编程 API笔记 - java.net 包相关 接口 api
- Android 网络编程 API笔记 - java.net 包相关 接口 api
- JDK 1.7 java.io 源码学习之AutoCloseable接口和try-with-resources语法
- 探究java IO之AutoCloseable,Closeable和Flushable接口
- 【Android 应用开发】Android 网络编程 API笔记 - java.net 包相关 接口 api
- JDK 1.7 java.io 源码学习之AutoCloseable接口和try-with-resources语法
- JDK 1.7 java.io 源码学习之Closeable、Flushable、Appendable接口
- 探究java IO之AutoCloseable,Closeable和Flushable接口
- 【Android 应用开发】Android 网络编程 API笔记 - java.net 包相关 接口 api
- Android 网络编程 API笔记 - java.net 包相关 接口 api
- 软件包 java.io 的分层结构(http://gceclub.sun.com.cn/Java_Docs/html/zh_CN/api/java/io/package-tree.html)
- Can not find a java.io.InputStream with the name [downloadFile] in the invocation stack问题解决
- 接口java.io.Serializable的用处 (全面搜集总结)
- Java IO 文件读写相关的操作
- java.IO.Serializable 接口是什么功能?