inputstream java_Java实现inputstream流的复制
獲取到一個(gè)inputstream后,可能要多次利用它進(jìn)行read的操作。由于流讀過(guò)一次就不能再讀了,而InputStream對(duì)象本身不能復(fù)制,而且它也沒(méi)有實(shí)現(xiàn)Cloneable接口,所以得想點(diǎn)辦法。
實(shí)現(xiàn)思路:
1、先把InputStream轉(zhuǎn)化成ByteArrayOutputStream
2、后面要使用InputStream對(duì)象時(shí),再?gòu)腂yteArrayOutputStream轉(zhuǎn)化回來(lái)
代碼實(shí)現(xiàn)如下:
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(); //這里可以寫(xiě)你獲取到的流
ByteArrayOutputStream baos = cloneInputStream(input);
// 打開(kāi)兩個(gè)新的輸入流
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;
}
}
}
這種適用于一些不是很大的流,因?yàn)榫彺媪魇菚?huì)消耗內(nèi)存的。
關(guān)于InputStream為什么不能被重復(fù)讀取?
首先,熟悉Java的人可能都知道,Java中的Inputstream是不能重復(fù)讀取的。
但是有沒(méi)有想過(guò),InputStream為什么不能重復(fù)讀呢?
其實(shí)要回答“為什么”這個(gè)問(wèn)題很簡(jiǎn)單,就是人家接口就是這么設(shè)計(jì)的,不能重復(fù)讀。
所以今天要討論的問(wèn)題更像是:Java的InputStream為什么要設(shè)計(jì)為不能重復(fù)讀?
關(guān)于InputStream為什么不能重復(fù)讀取,網(wǎng)上也各有說(shuō)法:
有的同學(xué)說(shuō):
“InputStream就類(lèi)比成一個(gè)杯子,杯子里的水就像InputStream里的數(shù)據(jù),你把杯子里的水拿出來(lái)了,杯子的水就沒(méi)有了,InputStream也是同樣的道理。”
比喻的非常好,讓我們從直觀(guān)上認(rèn)識(shí)了InputStream為什么不能重復(fù)被讀。
也有的同學(xué)從更深的代碼角度去分析:
“在InputStream讀取的時(shí)候,會(huì)有一個(gè)pos指針,他指示每次讀取之后下一次要讀取的起始位置,當(dāng)讀到最后一個(gè)字符的時(shí)候,pos指針不會(huì)重置。”
說(shuō)的也有道理,就是說(shuō)InputStream的讀取是單向的。但是并不是所有的InputStream實(shí)現(xiàn)類(lèi)都是這樣的實(shí)現(xiàn)方式。
//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內(nèi)部是使用數(shù)組實(shí)現(xiàn)的,遍歷的時(shí)候也有一個(gè)pos指針。但是沒(méi)有說(shuō)List遍歷一個(gè)第二次遍歷就沒(méi)有了。第二次遍歷是創(chuàng)建新的Iterator,所以pos也回到了數(shù)組起始位置。對(duì)于某些InputStream當(dāng)然可以也這么做。例如:ByteArrayInputStream
ByteArrayInputStream就是將一個(gè)Java的byte數(shù)組保存到對(duì)象里,然后讀取的時(shí)候遍歷該byte數(shù)組。
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而言,要實(shí)現(xiàn)重復(fù)讀取是很簡(jiǎn)單的,但是為什么沒(méi)有。我想是為了遵循InputStream的統(tǒng)一標(biāo)準(zhǔn)。
在InputStream的read方法的注釋上明確說(shuō)明:
/**
* 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;
當(dāng)流到達(dá)末尾后,返回-1.
其實(shí)像FileInputStream這樣的文件流,要實(shí)現(xiàn)重復(fù)使用可能也并不是很難,利用緩存什么的應(yīng)該能做到(大文件讀取就悲劇了,呵呵呵)。
但是InputStream顧名思義就是一個(gè)單向的字節(jié)流,跟水流一樣,要想再次使用就自己再去源頭取一下。
InputStream其實(shí)不像杯子,更像是一根水管,要想喝水了,就在把水管架在水源與杯子之間,讓水流到杯子里(注意:這個(gè)動(dòng)作完成了之后水管里面就沒(méi)有水了)。
這樣看來(lái),InputStream其實(shí)是一個(gè)數(shù)據(jù)通道,只負(fù)責(zé)數(shù)據(jù)的流通,并不負(fù)責(zé)數(shù)據(jù)的處理和存儲(chǔ)等其他工作范疇。
前面講過(guò),其實(shí)有的InputStream實(shí)現(xiàn)類(lèi)是可以實(shí)現(xiàn)數(shù)據(jù)的處理工作的。但是沒(méi)有這么做,這就是規(guī)范和標(biāo)準(zhǔn)的重要性。
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的inputstream java_Java实现inputstream流的复制的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 京东黄金和博时黄金的区别,划重点啦!
- 下一篇: java 内部编码_Java 中文编码分