[英]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);
}
doStuff1
, doStuff2
和doStuff3
都需要在相同的字節上工作,但做不同的事情。 我也假設這些函數可以是異步的。
我知道可以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.