簡體   English   中英

從具有大量數據的Java InputStream中讀取多次

[英]Read from a Java InputStream with very large amounts of data multiple times

我想知道從Java InputStream多次讀取字節的最佳方法是什么,並且當流非常大時仍然有效。 假設我有以下代碼:

public void handleBytes(InputStream in) {
    doStuff1(in);
    doStuff2(in);
    doStuff3(in);
}

doStuff1doStuff2doStuff3都需要在相同的字節上工作,但做不同的事情。 我也假設這些函數可以是異步的。

我知道可以mark然后reset流,但我想知道這是否是in有大量數據時的方法。 另外,如果我想每個doStuff-X都有一個線程工作者,我真的不能使用reset

我應該為每個doStuff-X方法獲得流的副本嗎? 但話又說回來,我不確定它會對大量數據有效。

您只能在不緩沖整個輸入的情況下讀取一次InputStream。

如果它是GB左右,您可以將其加載到內存中,或者將其復制到文件中並在有許多GB時重放它。 如果您可以在一個線程中解析數據,則可以將其傳遞給其他線程。

一般來說,這似乎是一個壞主意。 並不保證流完全支持mark ,即使支持mark ,也必須指定一個限制,在調用reset之前可以讀取多少字節。

既然你提到那些dostuff可以異步運行,為什么不為每個dostuff啟動一個線程並使用隊列同時將主線程的輸入提供給這三個隊列呢? 它需要一些同步,但這樣您對輸入音量沒有限制,仍然可以限制內存使用。

如果您知道三個doStuff()函數是異步運行的,那么您可以嘗試使用Apache Commons IO TeeInputStream將初始InputStream的內容復制到PipedOutputStream ,該PipedOutputStream連接到由doStuff2()讀取的PipedInputStream 同樣,您可以使用連接到doStuff3()的第二個PipedInputStream的第二個PipedOutputStream來設置第二個TeeInputStream。

這種方法有一些限制:

1)doStuff1(),doStuff2()和doStuff3()必須在不同的線程上運行,否則你將在doStuff1()運行時和doStuff2()和doStuff3()運行之前緩沖整個文件兩次。 這種方法假設doStuff2()和doStuff3()正在讀取和處理數據,而doStuff1()最初正在讀取數據。

2)doStuff1()不能使用skip(),mark()或reset(),因為這會弄亂下游函數(如TeeInputStream javadoc中所述)。

只要所有三個doStuff()函數都能以大致相同的速率處理數據,這種方法應該具有合理的內存效率。

您可以采用PipedOutputStream和PipedInputStream。

static class Task extends Thread{
    private final String taskName;
    private final BufferedInputStream input;
    public Task(String taskName, PipedInputStream input){
        this.taskName = taskName;
        this.input = new BufferedInputStream( input);
    }

    public void run(){
        try {
            System.out.println("Thread "+this.taskName+" Start");

            final byte buf[] = new byte[8]; // 8 bytes for demo
            while(true){
                if( input.available() > 0){
                    input.read(buf);
                    System.out.println(String.format("Task Name %s, read:%s", this.taskName, new String(buf)));
                }
                else{
                    // TODO: Set break Condition:Ex: Check the expected read size
                    Thread.sleep(1000);
                }
            }
        } catch (IOException | InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}
public static void main(String args[]) {
    try{
        final PipedInputStream input1 = new PipedInputStream();
        final PipedInputStream input2 = new PipedInputStream();
        final PipedInputStream input3 = new PipedInputStream();

        final Task t1 = new Task("Task1", input1);
        final Task t2 = new Task("Task2", input2);
        final Task t3 = new Task("Task3", input3);
        t1.start();
        t2.start();
        t3.start();

        Thread.sleep(300);

        InputStream input = null;
        try{
            input = new FileInputStream("LargeInputFile.txt");

            final PipedOutputStream out1 = new PipedOutputStream(input1);
            final PipedOutputStream out2 = new PipedOutputStream(input2);
            final PipedOutputStream out3 = new PipedOutputStream(input3);

            byte buf[] = new byte[8]; // 8 bytes for demo
            while(true){

                if(input.available()>0){
                    int size = input.read(buf);

                    if(size > 0){
                        out1.write(buf);
                        out2.write(buf);
                        out3.write(buf);
                        out1.flush();
                        out2.flush();
                        out3.flush();
                    }                       
                }
                else{
                    System.out.println("Rread is finished!");
                    break;
                }
            }
        }
        finally{
            if(input!=null){
                input.close();
            }
        }   
        t1.join();
        t2.join();
        t3.join();
    }
    catch(Exception e){
        e.printStackTrace(System.err);
    }
}

暫無
暫無

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

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