2010-11-25 5 views
7

Java'da bir alt işlem oluşturmak için Runtime exec() yöntemini kullanıyorum. Ancak, alt süreç interaktif bir program olduğundan, ona gerektiği şekilde ve gerektiği şekilde girdi sağlamalıyım. Ayrıca alt işlemin çıktısını göstermem gerekiyor. Bunu en basit şekilde nasıl yapabilirim?Bir alt işlemi çalıştırın, Java'da doğru bir şekilde giriş ve çıkış sağlayın

Process.getInputStream() yöntemini kullanarak program çıktısını göstermek için bir StreamGobbler kullanıyordum. Bununla birlikte, programın ne zaman girdi beklediğini ve proc.getOutputStream kullanarak ne zaman girdi sağlayacağını bilmiyorum. Bunu nasıl yapabilirim?

cevap

2

Sen altişlem akışları ve System akışları (System.in, System.out ve System.err) arasındaki giriş ve çıkışını kopyalamanız gerekir. Bu my recent quesion ile ilgilidir. Şimdiye kadar bulduk en iyi çözümdür:

import java.io.FileInputStream; 
import java.io.FilterInputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.lang.reflect.Field; 
import java.nio.ByteBuffer; 
import java.nio.channels.AsynchronousCloseException; 
import java.nio.channels.FileChannel; 

class StreamCopier implements Runnable { 
    private InputStream in; 
    private OutputStream out; 

    public StreamCopier(InputStream in, OutputStream out) { 
     this.in = in; 
     this.out = out; 
    } 

    public void run() { 
     try { 
      int n; 
      byte[] buffer = new byte[4096]; 
      while ((n = in.read(buffer)) != -1) { 
       out.write(buffer, 0, n); 
       out.flush(); 
      } 
     } 
     catch (IOException e) { 
      System.out.println(e); 
     } 
    } 
} 

class InputCopier implements Runnable { 
    private FileChannel in; 
    private OutputStream out; 

    public InputCopier(FileChannel in, OutputStream out) { 
     this.in = in; 
     this.out = out; 
    } 

    public void run() { 
     try { 
      int n; 
      ByteBuffer buffer = ByteBuffer.allocate(4096); 
      while ((n = in.read(buffer)) != -1) { 
       out.write(buffer.array(), 0, n); 
       out.flush(); 
      } 
      out.close(); 
     } 
     catch (AsynchronousCloseException e) {} 
     catch (IOException e) { 
      System.out.println(e); 
     } 
    } 
} 

public class Test { 
    private static FileChannel getChannel(InputStream in) 
      throws NoSuchFieldException, IllegalAccessException { 
     Field f = FilterInputStream.class.getDeclaredField("in"); 
     f.setAccessible(true); 
     while (in instanceof FilterInputStream) 
      in = (InputStream)f.get((FilterInputStream)in); 
     return ((FileInputStream)in).getChannel(); 
    } 

    public static void main(String[] args) 
      throws IOException, InterruptedException, 
        NoSuchFieldException, IllegalAccessException { 
     Process process = Runtime.getRuntime().exec("sh -i +m"); 
     Thread outThread = new Thread(new StreamCopier(
       process.getInputStream(), System.out)); 
     outThread.start(); 
     Thread errThread = new Thread(new StreamCopier(
       process.getErrorStream(), System.err)); 
     errThread.start(); 
     Thread inThread = new Thread(new InputCopier(
       getChannel(System.in), process.getOutputStream())); 
     inThread.start(); 
     process.waitFor(); 
     System.in.close(); 
     outThread.join(); 
     errThread.join(); 
     inThread.join(); 
    } 
} 

burada zor kısmı System.in bir kanal çıkarmaktır. Bu olmadan, alt işlem sona erdiğinde girişi okuyan iş parçacığını kesemezsiniz.

Bu yaklaşımın ciddi bir dezavantajı vardır: System.in'u kapattıktan sonra artık okuyamazsınız. Şu anda kullandığım geçici çözüm, tüm alt işlemlerde kullanılan tek bir giriş yönlendirme iş parçacığına sahip olmaktır.

2

Kendinize sorun "Komut satırından çalıştırdığımda programın ne zaman giriş istediğini nasıl anlarım?" Ne istediğini görüyorsunuz ve bu istemi temel alarak veriyi giriyorsunuz. İlke aynı olacaktır, ancak kodunuzun programın çıktısını yorumlaması ve doğru girişi sağlaması gerekecektir. Tekerleği yeniden icat önlemek için

, programlı etkileşim bu tür işlemek için tasarlanmış saygıdeğer * Nix Expect aracı Java uygulamaları olan, ExpectJ ve/veya Expect4J bakabilirsiniz.

+0

Benzer bir sorunla karşılaştı ve ExpectJ kullanarak çözdüm. Çok sezgisel bir kütüphane, çalışmasını sağlamak için beni 5 dakika gibi aldı. İyi tavsiye +1 – codelidoo

İlgili konular