如何克隆输入流?
我有一个输入流,我将其传递给一个方法来进行一些处理。我将在其他方法中使用相同的InputStream,但是在第一次处理之后,InputStream在方法内部出现关闭。
我如何克隆InputStream以发送到关闭他的方法?还有其他解决方案吗?
编辑:关闭输入流的方法是来自库的外部方法。我无法控制是否关闭。
private String getContent(HttpURLConnection con) {
InputStream content = null;
String charset = "";
try {
content = con.getInputStream();
CloseShieldInputStream csContent = new CloseShieldInputStream(content);
charset = getCharset(csContent);
return IOUtils.toString(content,charset);
} catch (Exception e) {
System.out.println("Error downloading page: " + e);
return null;
}
}
private String getCharset(InputStream content) {
try {
Source parser = new Source(content);
return parser.getEncoding();
} catch (Exception e) {
System.out.println("Error determining charset: " + e);
return "UTF-8";
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
如果您只想多次读取相同的信息,并且输入数据足够小以适合内存,则可以将数据从
InputStream
复制到 ByteArrayOutputStream。然后,您可以获得关联的字节数组并打开尽可能多的“克隆” ByteArrayInputStream,如您所愿。
但如果您确实需要保持原始流打开以接收新数据,那么您将需要跟踪对
close()
的外部调用。您需要以某种方式防止close()
被调用。更新(2019):
从 Java 9 开始,中间位可以替换为
InputStream.transferTo
:If all you want to do is read the same information more than once, and the input data is small enough to fit into memory, you can copy the data from your
InputStream
to a ByteArrayOutputStream.Then you can obtain the associated array of bytes and open as many "cloned" ByteArrayInputStreams as you like.
But if you really need to keep the original stream open to receive new data, then you will need to track the external call to
close()
. You will need to preventclose()
from being called somehow.UPDATE (2019):
Since Java 9 the the middle bits can be replaced with
InputStream.transferTo
:您想使用 Apache 的
CloseShieldInputStream
:这是一个包装器,可防止流被关闭。你会做这样的事情。
You want to use Apache's
CloseShieldInputStream
:This is a wrapper that will prevent the stream from being closed. You'd do something like this.
您无法克隆它,并且如何解决问题取决于数据的来源。
一种解决方案是将所有数据从 InputStream 读取到字节数组中,然后围绕该字节数组创建一个 ByteArrayInputStream,并将该输入流传递到您的方法中。
编辑1:
也就是说,如果其他方法也需要读取相同的数据。即您想要“重置”流。
You can't clone it, and how you are going to solve your problem depends on what the source of the data is.
One solution is to read all data from the InputStream into a byte array, and then create a ByteArrayInputStream around that byte array, and pass that input stream into your method.
Edit 1:
That is, if the other method also needs to read the same data. I.e you want to "reset" the stream.
如果从流中读取的数据很大,我建议使用 Apache Commons IO 中的 TeeInputStream。这样,您基本上可以复制输入并传递 td 管道作为您的克隆。
If the data read from the stream is large, I would recommend using a TeeInputStream from Apache Commons IO. That way you can essentially replicate the input and pass a t'd pipe as your clone.
这可能不适用于所有情况,但这就是我所做的:我扩展了 FilterInputStream 类并在外部库读取数据时对字节进行所需的处理。
然后,您只需传递一个 StreamBytesWithExtraProcessingInputStream 实例,您将在其中传递输入流。使用原始输入流作为构造函数参数。
应该注意的是,这是逐字节工作的,因此如果需要高性能,请不要使用它。
This might not work in all situations, but here is what I did: I extended the FilterInputStream class and do the required processing of the bytes as the external lib reads the data.
Then you simply pass an instance of
StreamBytesWithExtraProcessingInputStream
where you would have passed in the input stream. With the original input stream as constructor parameter.It should be noted that this works byte for byte, so don't use this if high performance is a requirement.
UPD。
之前看了一下评论。这不完全是所问的内容。
如果您使用的是 apache.commons ,您可以使用 IOUtils 复制流。
您可以使用以下代码:
这是适合您情况的完整示例:
此代码需要一些依赖项:
MAVEN
GRADLE
以下是此方法的 DOC 参考:
您可以在此处找到有关
IOUtils
的更多信息:http://commons.apache.org/proper/commons-io/javadocs/api-2.4/org/apache/commons/io/IOUtils.html#toBufferedInputStream(java.io.InputStream)
UPD.
Check the comment before. It isn't exactly what was asked.
If you are using
apache.commons
you may copy streams usingIOUtils
.You can use following code:
Here is the full example suitable for your situation:
This code requires some dependencies:
MAVEN
GRADLE
Here is the DOC reference for this method:
You can find more about
IOUtils
here:http://commons.apache.org/proper/commons-io/javadocs/api-2.4/org/apache/commons/io/IOUtils.html#toBufferedInputStream(java.io.InputStream)
下面是 Kotlin 的解决方案。
您可以将InputStream复制到ByteArray中。
如果您需要多次读取
byteInputStream
,请在再次读取之前调用byteInputStream.reset()
。https://code.luasoftware.com/tutorials/kotlin/how - 克隆输入流/
Below is the solution with Kotlin.
You can copy your InputStream into ByteArray
If you need to read the
byteInputStream
multiple times, callbyteInputStream.reset()
before reading again.https://code.luasoftware.com/tutorials/kotlin/how-to-clone-inputstream/
克隆输入流可能不是一个好主意,因为这需要深入了解所克隆的输入流的详细信息。解决此问题的方法是创建一个新的输入流,再次从同一源读取。
因此,使用某些 Java 8 功能,情况将如下所示:
此方法具有积极的效果,它将重用已存在的代码 - 创建封装在
inputStreamSupplier
中的输入流。并且不需要为流的克隆维护第二个代码路径。另一方面,如果从流中读取数据的成本很高(因为它是通过低带宽连接完成的),那么此方法将使成本加倍。这可以通过使用特定的供应商来规避,该供应商将首先在本地存储流内容并为现在的本地资源提供一个
InputStream
。Cloning an input stream might not be a good idea, because this requires deep knowledge about the details of the input stream being cloned. A workaround for this is to create a new input stream that reads from the same source again.
So using some Java 8 features this would look like this:
This method has the positive effect that it will reuse code that is already in place - the creation of the input stream encapsulated in
inputStreamSupplier
. And there is no need to maintain a second code path for the cloning of the stream.On the other hand, if reading from the stream is expensive (because a it's done over a low bandwith connection), then this method will double the costs. This could be circumvented by using a specific supplier that will store the stream content locally first and provide an
InputStream
for that now local resource.下面的课程应该可以解决这个问题。只需创建一个实例,调用“乘法”方法,并提供源输入流和所需的重复项数量。
重要提示:您必须在单独的线程中同时使用所有克隆流。
The class below should do the trick. Just create an instance, call the "multiply" method, and provide the source input stream and the amount of duplicates you need.
Important: you must consume all cloned streams simultaneously in separate threads.
通过示例增强
@Anthony Accioly
。完整示例:
Enhancing the
@Anthony Accioly
with the example.Full Example:
如果InputStream不太大,可以使用org.apache.commons.io.IOUtils轻松读取字节并保存在内存中,以供以后多次使用:
if InputStream is not too big, use org.apache.commons.io.IOUtils to easily read bytes and save in memory, for use later many times: