繁体   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