Java I/O全文摘要(三)基本I/O,输入流

15 篇文章 0 订阅
12 篇文章 0 订阅

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);
    }
  }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值