简体   繁体   English

java InputStream 可以连续从方法中读取数据吗?

[英]Can a java InputStream continuously read data from a method?

I have a piece of code我有一段代码

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

and this line makes string "test" an input for an InputStream, however this is a static InputStream.并且这一行使字符串“test”成为 InputStream 的输入,但这是一个静态 InputStream。 is there any way without a Scanner, System.in or user external input to make this InputStream dynamic没有 Scanner、System.in 或用户外部输入,有什么方法可以使这个 InputStream 动态化

what I need is something like this我需要的是这样的

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

I've tried something like this我试过这样的事情

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

So, if we have所以,如果我们有

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

This is also not dynamic input stream as a resource is already in a database.这也不是动态输入流,因为资源已经在数据库中。

You want a pipe.你想要一个管子。 Specifically, you want one of the following pairs of classes:具体来说,您需要以下一对类之一:

Your question asks for an InputStream, but since you're dealing with text, you probably should use a Reader, which is intended for characters.您的问题要求使用 InputStream,但由于您正在处理文本,因此您可能应该使用 Reader,它适用于字符。 In particular, note that getBytes() will return different values on Windows systems compared to non-Windows systems, for any String with non-ASCII characters.特别要注意,对于任何带有非 ASCII 字符的字符串,与非 Windows 系统相比, getBytes()在 Windows 系统上将返回不同的值 Using a Reader and Writer will remove the need to worry about that.使用 Reader 和 Writer 将消除担心的需要。

Either way, the approach is the same: create the readable end of the pipe, then create and feed the writable end of the pipe in another thread.无论哪种方式,方法都是相同的:创建管道的可读端,然后在另一个线程中创建并提供管道的可写端。

Using a PipedReader and PipedWriter:使用 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;
}

Using a PipedInputStream and PipedOutputStream:使用 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 PipedInputStream(pipedinputStream),
            StandardCharsets.UTF_8)) {

        writer.write("<test>");

        for (int i = 0; i < 1000; i++) {
            writer.write("<str>" + i + "</str>");
        }

        writer.write("</test>");
    }

    return null;
}

Sure.当然。 But you have a bit of an issue: Whatever code is generating the endless stream of dynamic data cannot just be in the method that 'returns the inputstream' just by itself, that's what your realisation is about.但是您有一个问题:无论代码生成无穷无尽的动态数据流,都不能仅存在于“返回输入流”的方法中,这就是您的实现。

You have two major options:您有两个主要选择:

Threads线程

Instead, you could fire off a thread which is continually generating data.相反,您可以触发一个不断生成数据的线程。 Note that whatever it 'generates' needs to be cached;请注意,它“生成”的任何内容都需要缓存; this is not a good fit if, say, you want to dynamically generate an inputstream that just serves up an endless amount of 0 bytes, for example.例如,如果您想动态生成一个只提供无限量 0 字节的输入流,这不是一个很好的选择 It's a good fit if the data is coming from, say, a USB connected arduino that from time to time sends information about a temperature sensor that it's connected to.如果数据来自 USB 连接的 arduino,它会不时发送有关它所连接的温度传感器的信息,那么这是一个很好的选择。 Note that you need the thread to store the data it receives someplace, and then have an inputstream that will 'pull' from this queue of data you're making.请注意,您需要线程将它接收到的数据存储在某个地方,然后有一个输入流从您正在制作的这个数据队列中“拉出”。 To make an inputstream that pulls from a queue, see the next section.要创建从队列中拉取的输入流,请参阅下一节。 As this will involve threads, use something from java.util.concurrent , such as ArrayBlockingQueue - this has the double benefit that you won't get infinite buffers, either (the act of putting something in the buffer will block if the buffer is full).由于这将涉及线程,因此请使用java.util.concurrent某些内容,例如ArrayBlockingQueue - 这具有双重好处,您也不会获得无限缓冲区(如果缓冲区已满,则将某些内容放入缓冲区的行为将阻塞)。

subclassing子类化

What you can also do is take the code that can generate new values, but, put it in an envelope - a thing you can pass around.你还可以做的是获取可以生成新值的代码,但是,把它放在一个信封里——你可以传递的东西。 You want to make some code, but not run it - you want to run that later, when the thing you hand the inputstream to, calls .read() .您想编写一些代码,但运行它 - 您想稍后运行该代码,当您将.read() ,调用.read()

One easy way to do that, is to extend InputStream - and then implement your own zero method.一种简单的方法是扩展 InputStream - 然后实现您自己的零方法。 Looks something like this:看起来像这样:


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

It's that simple.就这么简单。 Given:鉴于:

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.
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM