2010-11-14 6 views
7

यह this question का पालन करता है। जवाब का सुझाव दिया हैप्रक्रिया के इनपुट/आउटपुट धाराओं को उनके सिस्टम समकक्षों की प्रतिलिपि कैसे कॉपी करें?

प्रक्रिया बाहर कॉपी करने के लिए, अरे, और इनपुट के रूप में निम्नानुसार (विभिन्न संकलन त्रुटियों को ठीक करने के बाद) सिस्टम संस्करणों

स्ट्रीम करता IOUtils.copy साथ:

import org.apache.commons.io.IOUtils; 
import java.io.IOException; 

public class Test { 
    public static void main(String[] args) 
      throws IOException, InterruptedException { 
     final Process process = Runtime.getRuntime().exec("/bin/sh -i"); 
     new Thread(new Runnable() {public void run() { 
      try { 
       IOUtils.copy(process.getInputStream(), System.out); 
      } catch (IOException e) {} 
     } }).start(); 
     new Thread(new Runnable() {public void run() { 
      try { 
       IOUtils.copy(process.getErrorStream(), System.err); 
      } catch (IOException e) {} 
     } }).start(); 
     new Thread(new Runnable() {public void run() { 
      try { 
       IOUtils.copy(System.in, process.getOutputStream()); 
      } catch (IOException e) {} 
     } }).start(); 
     process.waitFor(); 
    } 
} 

हालांकि, परिणामी कोड इंटरैक्टिव प्रक्रियाओं के लिए काम नहीं करता है जैसे कि sh -i कमांड निष्पादित करता है। बाद के मामले में sh आदेशों में से कोई भी प्रतिक्रिया नहीं है।

तो मेरा सवाल यह है कि: क्या आप उन धाराओं की प्रतिलिपि बनाने का विकल्प सुझा सकते हैं जो इंटरैक्टिव प्रक्रियाओं के साथ काम करेंगे?

उत्तर

5

समस्या यह है कि IOUtil.copy() चल रहा है जबकि इनपुटस्ट्रीम में डेटा कॉपी किया जा रहा है। चूंकि आपकी प्रक्रिया समय-समय पर डेटा उत्पन्न करती है, IOUtil.copy() निकलती है क्योंकि ऐसा लगता है कि प्रतिलिपि बनाने के लिए कोई डेटा नहीं है।

बस हाथ से डेटा कॉपी और बाहर धागा प्रपत्र को रोकने के लिए एक बूलियन का उपयोग करें:

byte[] buf = new byte[1024]; 
int len; 
while (threadRunning) { // threadRunning is a boolean set outside of your thread 
    if((len = input.read(buf)) > 0){ 
     output.write(buf, 0, len); 
    } 
} 

यह मात्रा में पढ़ता है के रूप में कई बाइट्स के रूप में वहाँ InputStream और उत्पादन के लिए प्रतियां उन सभी पर उपलब्ध हैं। आंतरिक इनपुटस्ट्रीम थ्रेड को wait() रखता है और फिर डेटा उपलब्ध होने पर इसे जागता है।
तो यह उतना ही कुशल है जितना आप इस स्थिति में कर सकते हैं।

+1

सुझाव के लिए धन्यवाद। हालांकि 'IOUtil.copy()' स्ट्रीम के अंत तक पहुंचने तक बाहर नहीं निकलता है, इसलिए यह आपके कोड से अलग नहीं है जिसमें 'sh' के साथ समान समस्याएं हैं। – vitaut

+0

Pls इस http://stackoverflow.com/questions/804951/is-it-possible-to-read-from-a-java-inputstream-with-a-timeout/808795#808795 पर एक नज़र डालें –

1

Process.getOutputStream() रिटर्न एक BufferedOutputStream, इसलिए यदि आप करने के लिए अपने इनपुट चाहते हैं वास्तव में उपप्रक्रिया आप हर write() के बाद flush() फोन करने के लिए मिलता है।

आप भी अपने उदाहरण पुनर्लेखन एक धागे पर सब कुछ करने के लिए कर सकते हैं (हालांकि यह मतदान का उपयोग करता है दोनों System.in और प्रक्रिया 'एक ही समय में stdout को पढ़ने के लिए):

import java.io.*; 

public class TestProcessIO { 

    public static boolean isAlive(Process p) { 
    try { 
     p.exitValue(); 
     return false; 
    } 
    catch (IllegalThreadStateException e) { 
     return true; 
    } 
    } 

    public static void main(String[] args) throws IOException { 
    ProcessBuilder builder = new ProcessBuilder("bash", "-i"); 
    builder.redirectErrorStream(true); // so we can ignore the error stream 
    Process process = builder.start(); 
    InputStream out = process.getInputStream(); 
    OutputStream in = process.getOutputStream(); 

    byte[] buffer = new byte[4000]; 
    while (isAlive(process)) { 
     int no = out.available(); 
     if (no > 0) { 
     int n = out.read(buffer, 0, Math.min(no, buffer.length)); 
     System.out.println(new String(buffer, 0, n)); 
     } 

     int ni = System.in.available(); 
     if (ni > 0) { 
     int n = System.in.read(buffer, 0, Math.min(ni, buffer.length)); 
     in.write(buffer, 0, n); 
     in.flush(); 
     } 

     try { 
     Thread.sleep(10); 
     } 
     catch (InterruptedException e) { 
     } 
    } 

    System.out.println(process.exitValue()); 
    } 
} 
1

आप के बजाय का उपयोग करना चाहिए ProcessBuilder.redirectOutput विधि & दोस्त। और पढ़ें here

संबंधित मुद्दे