2009-03-18 5 views
15

मैं जावा से एक प्रक्रिया लॉन्च करना चाहता हूं, इसके आउटपुट को पढ़ना चाहता हूं, और इसके रिटर्न कोड प्राप्त करना चाहता हूं। लेकिन जब यह निष्पादित हो रहा है, तो मैं इसे रद्द करने में सक्षम होना चाहता हूं। मैं इस प्रक्रिया शुरू करके बाहर शुरू:जावा से बाहरी प्रोग्राम चलाएं, आउटपुट पढ़ें, बाधा

ProcessBuilder pb = new ProcessBuilder(args); 
pb.redirectErrorStream(true); 
Process proc = pb.start(); 

अगर मैं proc.waitFor फोन(), मैं इस प्रक्रिया से बाहर निकलता है जब तक कुछ नहीं कर सकते। तो मुझे लगता है कि मुझे ऐसा कुछ करने की ज़रूरत है:

while (true) { 
    see if process has exited 
    capture some output from the process 
    decide if I want to cancel it, and if so, cancel it 
    sleep for a while 
} 

क्या यह सही है? क्या कोई मुझे जावा में ऐसा करने का उदाहरण दे सकता है?

उत्तर

11

यहाँ मैं क्या लगता है कि आप क्या करना चाहते हैं का एक उदाहरण है:

ProcessBuilder pb = new ProcessBuilder(args); 
pb.redirectErrorStream(true); 
Process proc = pb.start(); 

InputStream is = proc.getInputStream(); 
InputStreamReader isr = new InputStreamReader(is); 
BufferedReader br = new BufferedReader(isr); 

String line; 
int exit = -1; 

while ((line = br.readLine()) != null) { 
    // Outputs your process execution 
    System.out.println(line); 
    try { 
     exit = proc.exitValue(); 
     if (exit == 0) { 
      // Process finished 
     } 
    } catch (IllegalThreadStateException t) { 
     // The process has not yet finished. 
     // Should we stop it? 
     if (processMustStop()) 
      // processMustStop can return true 
      // after time out, for example. 
      proc.destroy(); 
    } 
} 

आप इसे सुधार कर सकते हैं :-) मैं अब यह परीक्षण करने के लिए एक वास्तविक वातावरण की जरूरत नहीं है, लेकिन आप कुछ और अधिक जानकारी प्राप्त कर सकते here। आप का वर्णन बिल्कुल के रूप में

public class ProcessWatcher implements Runnable { 

    private Process p; 
    private volatile boolean finished = false; 

    public ProcessWatcher(Process p) { 
     this.p = p; 
     new Thread(this).start(); 
    } 

    public boolean isFinished() { 
     return finished; 
    } 

    public void run() { 
     try { 
      p.waitFor(); 
     } catch (Exception e) {} 
     finished = true; 
    } 

} 

तब आप अपने पाश को क्रियान्वित करेगी::

+2

यदि कुछ समय के लिए कोई आउटपुट नहीं है तो क्या होगा?क्या यह ब्र्रेडलाइन() पर लटका नहीं होगा जब तक कि पढ़ने के लिए तैयार कोई लाइन न हो? मुझे यकीन नहीं है कि मेरी प्रक्रिया कितनी या कम आउटपुट भेजेगी। –

+2

गो पॉइंट। प्रक्रिया को रोकने के लिए आप विश्लेषण करने के लिए एक अलग धागा बना सकते हैं। यह थोड़ी देर के लिए समानांतर चला सकता है और प्रक्रिया को नष्ट कर सकता है अगर यह कुछ समय (या किसी अन्य स्थिति) के लिए लटकता है। –

+0

(मेरा मतलब था "अच्छा बिंदु") –

5

इस तरह एक सहायक वर्ग चाल करना होगा

Process p = Runtime.getRuntime().exec("whatever command"); 
ProcessWatcher pw = new ProcessWatcher(p); 
InputStream output = p.getInputStream(); 
while(!pw.isFinished()) { 
    processOutput(output); 
    if(shouldCancel()) p.destroy(); 
    Thread.sleep(500); 
} 

की स्थिति आप को नष्ट करना चाहते हो जाएगा क्या पर निर्भर करता प्रक्रिया, आप इसे एक अलग धागे में करना चाह सकते हैं। अन्यथा, आप प्रक्रिया के लिए अधिक प्रोग्राम आउटपुट की प्रतीक्षा करते समय अवरुद्ध कर सकते हैं और वास्तव में इसे नष्ट करने का विकल्प कभी नहीं प्राप्त कर सकते हैं।

EDIT: मैकडॉवेल नीचे अपनी टिप्पणी में 100% सही है, इसलिए मैंने पूर्ण परिवर्तनीय अस्थिर बना दिया है।

+1

"समाप्त" चर को कम से कम "अस्थिर" घोषित किया जाना चाहिए। – McDowell

+0

यह मेरी चिंता है; क्या होगा यदि थोड़ी देर के लिए कोई आउटपुट न हो? अगर मैं BufferedReader.readLine() की तरह कुछ कहता हूं, तो मैं नहीं चाहता कि यह आउटपुट होने तक हमेशा के लिए लटकाए; मुझे रद्द करने का मौका चाहिए। –

+0

आप सार्वजनिक शून्य रन() { जबकि (! Pw.isFinished()) { (ifCancel()) p.destroy() के साथ एक नया रननेबल बना सकते हैं; थ्रेड.sleep (500); } } फिर नया थ्रेड (myrunnable) .start()। –

0

क्या आप प्रक्रिया को मारने का निर्णय लेते हैं - एक असीमित घटना (जैसे उपयोगकर्ता से इनपुट), या एक तुल्यकालिक घटना (उदाहरण के लिए, प्रक्रिया ने वह किया है जो आप करना चाहते थे)? मुझे लगता है कि यह पूर्व है - उपयोगकर्ता से इनपुट आपको सबप्रोसेस को रद्द करने का निर्णय लेता है।

इसके अलावा, आप सबप्रोसेस का उत्पादन करने की अपेक्षा कितनी आउटपुट करते हैं? यदि यह बहुत कुछ है, तो उपप्रोसेसर ब्लॉक कर सकता है यदि आप इसकी आउटपुट स्ट्रीम से पर्याप्त रूप से पर्याप्त नहीं पढ़ते हैं।

आपकी स्थिति भिन्न हो सकती है, लेकिन ऐसा लगता है कि आपको कम से कम दो अलग-अलग धागे की आवश्यकता होगी - एक यह तय करने के लिए कि प्रक्रिया को रद्द करना है या कोई है जो उपप्रोसेसर से आउटपुट को संभालता है।

में थोड़ा और अधिक विस्तार के लिए यहाँ एक नज़र: पहिया पुनः बनाने से बचने के लिए http://java.sun.com/developer/JDCTechTips/2005/tt0727.html#2

+0

मैं पहले से ही थ्रेड में चल रहा हूं, और उस थ्रेड के बाहर कोई भी रद्द करने का समय होने पर मेरे फ़ील्ड में से एक सेट करेगा। –

8

मैं बाहर Apache Commons Exec की जांच करें। इसमें कुछ अच्छी विशेषताएं हैं जैसे सिंक्रोनस बनाम एसिंक्रोनस निष्पादन, साथ ही वॉचडॉग प्रक्रिया को उत्पन्न करने के लिए एक मानक समाधान जो कि अटकने के मामले में निष्पादन को समाप्त करने में मदद कर सकता है।

+0

मैंने इसे लड़ा क्योंकि मैं एक "शुद्ध" प्रोग्राम चाहता था जो केवल मूल जेडीके का इस्तेमाल करता था। लेकिन आप सही हैं, इस तरह के तरीके बहुत बेहतर हैं और कई समस्याएं हल करती हैं जिन्हें मैं नहीं जानता था जब मैं अपना खुद का निर्माण करने की कोशिश करता था तब मैं साइन अप कर रहा था। – GojiraDeMonstah

2

कैसे इस बारे में (देखें कि यह कैसे jcabi-heroku-maven-plugin में काम करता है):

/** 
* Wait for the process to stop, logging its output in parallel. 
* @param process The process to wait for 
* @return Stdout produced by the process 
* @throws InterruptedException If interrupted in between 
*/ 
private String waitFor(final Process process) throws InterruptedException { 
    final BufferedReader reader = new BufferedReader(
     new InputStreamReader(process.getInputStream()) 
    ); 
    final CountDownLatch done = new CountDownLatch(1); 
    final StringBuffer stdout = new StringBuffer(); 
    new Thread(
     new VerboseRunnable(
      new Callable<Void>() { 
       @Override 
       public Void call() throws Exception { 
        while (true) { 
         final String line = reader.readLine(); 
         if (line == null) { 
          break; 
         } 
         System.out.println(">> " + line); 
         stdout.append(line); 
        } 
        done.countDown(); 
        return null; 
       } 
      }, 
      false 
     ) 
    ).start(); 
    try { 
     process.waitFor(); 
    } finally { 
     done.await(); 
     IOUtils.closeQuietly(reader); 
    } 
    return stdout.toString(); 
} 

ps। अब यह कार्यान्वयन वर्ग jcabi-log आर्टिफैक्ट से com.jcabi.log.VerboseProcess वर्ग के रूप में उपलब्ध है।

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