java InputStream能否连续读取方法中的数据



我有一段代码

...
InputStream inputStream = new BufferedInputStream(new ByteArrayInputStream("test".getBytes()));
...

并且这条线构成字符串";测试";InputStream的输入,但是这是一个静态InputStream。如果没有Scanner、System.in或用户外部输入,有什么方法可以使这个InputStream动态

我需要像这个一样的东西

...
InputStream inputStream = new BufferedInputStream(new 
ByteArrayInputStream(generateContinuousDynamicString().getBytes()));
// So, basically input stream will be blocked until generateContinuousDynamicString()
// returns a result?
...

我试过这种

private static byte[] generateContinuousDynamicString(String s) {
String t = "";
// here comes the realization
// that the source for an input stream 
// cannot be generated dynamically on the 
// fly it only can be read from already 
// existing (fully generated and available 
// resource). Am I right? Otherwise how 
// can I adjust this method in such a way that
// input stream would continuously have a new
// string to read from? 
for (int i = 0; i < 1000; i++){
t += "<str>"+s+i+"</str>";
}
return ("<test>"+t+"</test>").getBytes();
}

所以,如果我们有

...
InputStream inputStream = new BufferedInputStream(readFromADatabaseStream());
...

这也不是动态输入流,因为资源已经在数据库中了。

您想要一个管道具体来说,您需要以下成对类中的一个:

  • PipedInputStream和PipedOutputStream
  • PipedReader和PipedWriter

您的问题需要InputStream,但由于您处理的是文本,您可能应该使用针对字符的Reader。特别要注意的是,对于任何具有非ASCII字符的字符串,与非Windows系统相比,getBytes()在Windows系统上将返回不同的值。使用读写器将消除对此的担忧。

无论哪种方式,方法都是一样的:创建管道的可读端,然后在另一个线程中创建并馈送管道的可写端。

使用PipedReader和PipedWriter:

PipedReader pipedReader = new PipedReader();
Reader reader = new BufferedReader(pipedReader);
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> pipeFeeder = executor.submit(
() -> generateContinuousDynamicString(pipedReader));
// ...
private Void generateContinuousDynamicString(PipedReader pipedReader)
throws IOException {
try (Writer writer = new PipedWriter(pipedReader)) {
writer.write("<test>");
for (int i = 0; i < 1000; i++) {
writer.write("<str>" + i + "</str>");
}
writer.write("</test>");
}
return null;
}

使用PipedInputStream和PipedOutputStream:

PipedInputStream pipedInputStream = new PipedInputStream();
InputStream inputStream = new BufferedInputStream(pipedInputStream);
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> pipeFeeder = executor.submit(
() -> generateContinuousDynamicString(pipedInputStream));
// ...
private Void generateContinuousDynamicString(PipedInputStream pipedInputStream)
throws IOException {
Charset charset = StandardCharsets.UTF_8;
try (Writer writer = new OutputStreamWriter(
new PipedOutputStream(pipedInputStream),
StandardCharsets.UTF_8)) {
writer.write("<test>");
for (int i = 0; i < 1000; i++) {
writer.write("<str>" + i + "</str>");
}
writer.write("</test>");
}
return null;
}

当然。但你有一点问题:无论生成源源不断的动态数据的代码是什么,都不能只在"返回输入流"的方法中,这就是你的实现。

你有两个主要的选择:

线程

相反,您可以启动一个不断生成数据的线程。请注意,它"生成"的任何内容都需要缓存;例如,如果您想动态生成一个只提供无限数量的0字节的输入流,那么这就不太适合。如果数据来自,比如说,一个USB连接的arduino,它会不时发送关于它所连接的温度传感器的信息,这是一个很好的选择。请注意,你需要线程将它接收到的数据存储在某个地方,然后有一个输入流,它将从你正在制作的数据队列中"提取"。要制作从队列中提取的输入流,请参阅下一节。由于这将涉及线程,请使用java.util.concurrent中的一些东西,如ArrayBlockingQueue——这有双重好处,即不会获得无限的缓冲区(如果缓冲区已满,则在缓冲区中放入一些东西的行为将被阻止(。

子类化

你还可以做的是获取可以生成新值的代码,但是,把它放在信封里——这是一种你可以传递的东西。您想要生成一些代码,但运行它——您希望稍后在您将输入流交给的对象调用.read()时运行它。

一种简单的方法是扩展InputStream,然后实现自己的zero方法。看起来像这样:


class InfiniteZeroesInputStream extends InputStream {
public int read() {
return 0;
}
}

就这么简单。给定:

try (InputStream in = new InfiniteZeroesInputStream()) {
in.read(); // returns 0.. and will always do so.
byte[] b = new byte[65536];
in.read(b); // fills the whole array with zeroes.
}

最新更新