1. 输入流
java.io.InputStream是一个抽象类,它是所有输入流的超级类。
它声明了从流中读取数据的三个基本方法;
它也声明了关闭流,检查可用字节数,跳过一定字节数,设定用于回退的标记位置,以及决定是否支持回退和标记。
2 read()方法
read方法是InputStream最基本的方法,得到一个0~255的无符号数.
方法签名为:
public abstract int read( ) throws IOException
虽然读取得到的是byte,但是返回的确是int。
这是由于只使用byte时,只能表示-128~127.
方法可能会抛出异常,所以你需要捕获其可能抛出的IOException。
但是,当读取到达末尾时,它不会抛出异常,而是返回-1。
此外,大多数读取是没有超时限制的(网络流除外),所以如果你在干别的重要的事情,最好把I/O 放在单独的线程里。
3 从流中读取大块数据
输入和输出通常是程序性能的瓶颈,
从磁盘中读取数据通常比从内存中读取慢几百倍,因此减少读取次数能够有效提升性能。
所有覆盖了read的方法都是通过读取一大块连续数据到一个数组里。
public int read(byte[] data) throws IOException public int read(byte[] data, int offset, int length) throws IOException
默认的实现只是调足够多次read来填充数组.
而子类提供了更高效的实现,有些是native层面的。
4 计算可用字节数
有时,你需要在实际读到不可读byte前,知道还有多少字节可读。
方法签名为:
public int available() throws IOException
例如按如下方式使用:
try {
byte[] b = new byte[100];
int offset = 0;
while (offset < b.length) {
int a = System.in.available( );
int bytesRead = System.in.read(b, offset, a);
if (bytesRead == -1) break; // end of stream
offset += bytesRead;
}
catch (IOException ex) {
System.err.println("Couldn't read from System.in!");
}
但是这段代码中有一个潜在的问题。如果有超过数组边界的可读数据呢?
为了解决这个问题,可能有哪个傻子创建了等同于可读数据长度的数组:
try {
byte[] b = new byte[System.in.available( )];
System.in.read(b);
}
catch (IOException ex) {
System.err.println("Couldn't read from System.in!");
}
这在一个read时当然没问题,但是多个read就有问题了:将会导致创建过量的数组。
默认的java.io.InputStream的available( )方法总是返回0。
你无法确保子类覆盖了它,也有可能子类对它的实现是阻塞的,不论怎么说,你应该在单独的线程中来使用它。
5 跳过字节 Skipping Bytes
方法如下:
public long skip(long bytesToSkip) throws IOException
返回值是实际跳过值,它可能小于 bytesToSkip。
Skipping通常快于读取并丢弃他们。
6 关闭输入流
通过关闭,输入流像输出流一样释放掉native资源。
public void close( ) throws IOException
一但你关闭了一个流,你就不应该再读取它。否则大部分情况下会抛出一个 IOException。
也不是所有的流都需要关闭,例如System.in通常无须关闭。
然而,与网络或者文件的流通常都需要关闭。
为了确保关闭,你应该在finally中执行close操作。
7 标记和重置
并非所有的InputStream都支持标记和重置
public void mark(int readLimit)
public void reset( ) throws IOException
public boolean markSupported( )
如果markSupported为true则支持;如果为false则不支持,那么调用reset()将导致抛出 IOException,而mark什么也不做。
已知的支持类有:BufferedInputStream和ByteArrayInputStream
注意:这里的设计确实不是很好,因为不是所有子类都支持的方法不应该放在超类中,然后通过这种方式去实现。但是在Java1.0时代,面向对象的设计理念还没有被普遍接受,所以这样的设计就出来了。
8 有效率的流拷贝
使用1K左右的buffer
public static void copy(InputStream in, OutputStream out)
throws IOException {
byte[] buffer = new byte[1024];
while (true) {
int bytesRead = in.read(buffer);
if (bytesRead == -1) break;
out.write(buffer, 0, bytesRead);
}
}