簡體   English   中英

java InputStream 可以連續從方法中讀取數據嗎?

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

我有一段代碼

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

並且這一行使字符串“test”成為 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());
...

這也不是動態輸入流,因為資源已經在數據庫中。

你想要一個管子。 具體來說,您需要以下一對類之一:

您的問題要求使用 InputStream,但由於您正在處理文本,因此您可能應該使用 Reader,它適用於字符。 特別要注意,對於任何帶有非 ASCII 字符的字符串,與非 Windows 系統相比, getBytes()在 Windows 系統上將返回不同的值 使用 Reader 和 Writer 將消除擔心的需要。

無論哪種方式,方法都是相同的:創建管道的可讀端,然后在另一個線程中創建並提供管道的可寫端。

使用 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 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;
}

當然。 但是您有一個問題:無論代碼生成無窮無盡的動態數據流,都不能僅存在於“返回輸入流”的方法中,這就是您的實現。

您有兩個主要選擇:

線程

相反,您可以觸發一個不斷生成數據的線程。 請注意,它“生成”的任何內容都需要緩存; 例如,如果您想動態生成一個只提供無限量 0 字節的輸入流,這不是一個很好的選擇 如果數據來自 USB 連接的 arduino,它會不時發送有關它所連接的溫度傳感器的信息,那么這是一個很好的選擇。 請注意,您需要線程將它接收到的數據存儲在某個地方,然后有一個輸入流從您正在制作的這個數據隊列中“拉出”。 要創建從隊列中拉取的輸入流,請參閱下一節。 由於這將涉及線程,因此請使用java.util.concurrent某些內容,例如ArrayBlockingQueue - 這具有雙重好處,您也不會獲得無限緩沖區(如果緩沖區已滿,則將某些內容放入緩沖區的行為將阻塞)。

子類化

你還可以做的是獲取可以生成新值的代碼,但是,把它放在一個信封里——你可以傳遞的東西。 您想編寫一些代碼,但運行它 - 您想稍后運行該代碼,當您將.read() ,調用.read()

一種簡單的方法是擴展 InputStream - 然后實現您自己的零方法。 看起來像這樣:


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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM