inputstream java_Java实现inputstream流的复制

获取到一个inputstream后,可能要多次利用它进行read的操作。由于流读过一次就不能再读了,而InputStream对象本身不能复制,而且它也没有实现Cloneable接口,所以得想点办法。

实现思路:

1、先把InputStream转化成ByteArrayOutputStream

2、后面要使用InputStream对象时,再从ByteArrayOutputStream转化回来

代码实现如下:

package com.test;

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.io.InputStream;

public class StreamOperateUtil {

public static void main(String[] args) throws FileNotFoundException {

InputStream input = new FileInputStream("c:\\test.txt");

//InputStream input = httpconn.getInputStream(); //这里可以写你获取到的流

ByteArrayOutputStream baos = cloneInputStream(input);

// 打开两个新的输入流

InputStream stream1 = new ByteArrayInputStream(baos.toByteArray());

InputStream stream2 = new ByteArrayInputStream(baos.toByteArray());

}

private static ByteArrayOutputStream cloneInputStream(InputStream input) {

try {

ByteArrayOutputStream baos = new ByteArrayOutputStream();

byte[] buffer = new byte[1024];

int len;

while ((len = input.read(buffer)) > -1) {

baos.write(buffer, 0, len);

}

baos.flush();

return baos;

} catch (IOException e) {

e.printStackTrace();

return null;

}

}

}

这种适用于一些不是很大的流,因为缓存流是会消耗内存的。

关于InputStream为什么不能被重复读取?

首先,熟悉Java的人可能都知道,Java中的Inputstream是不能重复读取的。

但是有没有想过,InputStream为什么不能重复读呢?

其实要回答“为什么”这个问题很简单,就是人家接口就是这么设计的,不能重复读。

所以今天要讨论的问题更像是:Java的InputStream为什么要设计为不能重复读?

关于InputStream为什么不能重复读取,网上也各有说法:

有的同学说:

“InputStream就类比成一个杯子,杯子里的水就像InputStream里的数据,你把杯子里的水拿出来了,杯子的水就没有了,InputStream也是同样的道理。”

比喻的非常好,让我们从直观上认识了InputStream为什么不能重复被读。

也有的同学从更深的代码角度去分析:

“在InputStream读取的时候,会有一个pos指针,他指示每次读取之后下一次要读取的起始位置,当读到最后一个字符的时候,pos指针不会重置。”

说的也有道理,就是说InputStream的读取是单向的。但是并不是所有的InputStream实现类都是这样的实现方式。

//BufferedInputStream代码片段:

public synchronized int read() throws IOException {

if (pos >= count) {

fill();

if (pos >= count)

return -1;

}

return getBufIfOpen()[pos++] & 0xff;

}

//FileInputStream代码片段:

public native int read() throws IOException;

我们知道:

Java 的List内部是使用数组实现的,遍历的时候也有一个pos指针。但是没有说List遍历一个第二次遍历就没有了。第二次遍历是创建新的Iterator,所以pos也回到了数组起始位置。对于某些InputStream当然可以也这么做。例如:ByteArrayInputStream

ByteArrayInputStream就是将一个Java的byte数组保存到对象里,然后读取的时候遍历该byte数组。

public ByteArrayInputStream(byte buf[]) {

this.buf = buf;

this.pos = 0;

this.count = buf.length;

}

public synchronized int read() {

return (pos < count) ? (buf[pos++] & 0xff) : -1;

}

就ByteArrayInputStream而言,要实现重复读取是很简单的,但是为什么没有。我想是为了遵循InputStream的统一标准。

在InputStream的read方法的注释上明确说明:

/**

* Reads the next byte of data from the input stream. The value byte is

* returned as an int in the range 0 to

* 255. If no byte is available because the end of the stream

* has been reached, the value -1 is returned. This method

* blocks until input data is available, the end of the stream is detected,

* or an exception is thrown.

*

*

A subclass must provide an implementation of this method.

*

* @return the next byte of data, or -1 if the end of the

* stream is reached.

* @exception IOException if an I/O error occurs.

*/

public abstract int read() throws IOException;

当流到达末尾后,返回-1.

其实像FileInputStream这样的文件流,要实现重复使用可能也并不是很难,利用缓存什么的应该能做到(大文件读取就悲剧了,呵呵呵)。

但是InputStream顾名思义就是一个单向的字节流,跟水流一样,要想再次使用就自己再去源头取一下。

InputStream其实不像杯子,更像是一根水管,要想喝水了,就在把水管架在水源与杯子之间,让水流到杯子里(注意:这个动作完成了之后水管里面就没有水了)。

这样看来,InputStream其实是一个数据通道,只负责数据的流通,并不负责数据的处理和存储等其他工作范畴。

前面讲过,其实有的InputStream实现类是可以实现数据的处理工作的。但是没有这么做,这就是规范和标准的重要性。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值