2010-11-14 13 views
7

Bu, this question numaralı izindir. Cevap, err Süreci dışarı kopyalamakİşlemin girdi/çıktı akışlarını Sistemdeki meslektaşlarına nasıl kopyalarım?

de öne sürdü ve giriş aşağıdaki gibi (çeşitli derleme hataları düzeltmeden sonra) IOUtils.copy Sistem sürümleri

akışları:

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(); 
    } 
} 

Ancak, sonuç kod, sh -i komutunu çalıştıran gibi etkileşimli işlemler için çalışmaz. Sonraki durumda, sh komutlarından hiçbirine yanıt yoktur.

Benim sorum şu: etkileşimli süreçlerle çalışacak akışları kopyalamak için bir alternatif önerebilir misiniz?

cevap

5

Sorun, kopyalanacak InputStream öğesinde varken, IOUtil.copy()'un çalışmasıdır. Prosesiniz sadece kopyalanacak veri olmadığını düşündüğü için zaman zaman IOUtil.copy() çıkışlarından veri üretiyor.

Sadece elle veri kopyalamak ve dış diş şekli durdurmak için bir boole kullanın: InputStream ve çıkışına kopya hepsi mevcut bulunmaktadır Bu parçalar okur

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); 
    } 
} 

gibi birçok bayt olarak. Dahili olarak InputStream iş parçacığı wait()'a koyar ve veri mevcut olduğunda onu uyandırır.
Yani bu durumda alabildiğiniz kadar verimli.

+1

Öneriniz için teşekkürler. Ancak 'IOUtil.copy()', akış sonuna ulaşılana kadar çıkmaz, bu nedenle kodunuzdan 'sh' ile aynı sorunları olandan farklı değildir. – vitaut

+0

Pls bu http://stackoverflow.com/questions/804951/is-it-possible-to-read-from-a-java-inputstream-with-a-timeout/808795#808795 adresine bir göz atın. –

1

Process.getOutputStream() bir BufferedOutputStream döndürür, bu yüzden sizin girişi istiyorsanız aslında her write() sonra flush() aramak zorunda alt süreç olsun.

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

Bunun yerine kullanmalıdır: (Bu System.in ve aynı zamanda stdout süreci hem okumak için yoklama kullanır rağmen)

Ayrıca, bir iş parçacığı üzerinde her şeyi yapmak için örnek yazabiliriz ProcessBuilder.redirectOutput metodu & arkadaşlar. Devamını oku here