2013-04-04 15 views
5

UPDATE: I found a crucial part to why this probably isn't working! I used System.setOut(out); where out is a special PrintStream to a JTextAreaDrukowanie InputStream Java z procesu

Jest to kod, ale problem mam jest to, że informacje są drukowane tylko raz zakończyć proces.

public Constructor() { 
    main(); 
} 

private void main() { 
    btnStart.addActionListener(new ActionListener() { 
     public void actionPerformed(ActionEvent e) { 
      try { 
       ProcessBuilder builder = new ProcessBuilder("java", textFieldMemory.getText(), "-jar", myJar); 
       Process process = builder.start(); 
       InputStream inputStream = process.getInputStream(); 
       BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream), 1); 
       String line; 
       while ((line = bufferedReader.readLine()) != null) { 
        System.out.println(line); 
       } 
       inputStream.close(); 
       bufferedReader.close(); 
      } catch (IOException ioe) { 
       ioe.printStackTrace(); 
      } 
     } 
    }); 
} 

Prąd wyjściowy:

Line 1 
Line 2 
Line 3 
Line 4 
Line 5 

Jest to poprawne wyjście, ale to jest tylko drukowane jako jeden duży blok kiedy zakończyć proces.

Czy ktoś wie, co to jest problem? Jeśli tak, możesz pomóc mi wyjaśnić, dlaczego tak się dzieje, z góry dziękuję.

+2

Wyjście były buforowane w 'BufferedReader', spróbuj tylko czytanie zawartości z' InputStream' bezpośrednio, czy to sprawia, różnica – MadProgrammer

+1

Zgadzam się z @MadProgrammer, że problem jest prawdopodobnie z buforem. Sugerowałbym jednak ustawienie rozmiaru bufora 'BufferedReader' na 1 za pomocą [jego konstruktora dwóch parametrów] (http://docs.oracle.com/javase/6/docs/api/java/io/BufferedReader.html# BufferedReader% 28java.io.Reader,% 20int% 29): 'new BufferedReader (new InputStreamReader (inputStream), 1)' – DaoWen

+0

Czy byłoby lepiej używać pracy ByteArrayOutputStream? Jestem zupełnie nowy w strumieniach i to mnie podrażnia XD – Ciphor

Odpowiedz

8

Przetwarzanie strumienia wyjściowego procesu w oddzielnym wątku może pomóc tutaj. Chcemy także wyraźnie czekać na proces zakończyć przed kontynuowaniem swojej logiki:

ProcessBuilder builder = new ProcessBuilder("java", 
     textFieldMemory.getText(), "-jar", myJar); 
final Process process = builder.start(); 
final Thread ioThread = new Thread() { 
    @Override 
    public void run() { 
     try { 
      final BufferedReader reader = new BufferedReader(
        new InputStreamReader(process.getInputStream())); 
      String line = null; 
      while ((line = reader.readLine()) != null) { 
       System.out.println(line); 
      } 
      reader.close(); 
     } catch (final Exception e) { 
      e.printStackTrace(); 
     } 
    } 
}; 
ioThread.start(); 

process.waitFor(); 
+0

Nie działa dla mnie, tak jak powiedziałem, myślę, że to ma związek z tym, że przekierowałem wyjście konsoli do JTextArea. – Ciphor

+0

Tak, to bardzo ważny szczegół. Najprawdopodobniej musisz jednoznacznie przepłukać strumień przy każdym zapisie, a następnie wywołać odświeżenie JTextArea, aby uzyskać wyświetlanie w czasie rzeczywistym. – Perception

+0

Znalazłem coś interesującego, jeśli spojrzycie na mój oryginalny kod w pytaniu i przenieśliście 'inputStream.close();' do pętli while, z powodzeniem otrzymam pierwszą linię wydrukowaną w mojej 'JTextArea', a następnie strumień jest oczywiście zamknięty. – Ciphor

4

Zasadniczo, z czego niewiele informacji nie ma, to brzmi jak twój uruchomieniem procesu i czytanie InputStream z poziomu zdarzenia rozdzielający wątek .

Wszystko, co blokuje EDT, uniemożliwi przetwarzanie żądań zamiany, zamiast tego należy użyć czegoś takiego, jak SwingWorker, które ma funkcjonalność umożliwiającą aktualizację interfejsu użytkownika za pomocą EDT.

Spójrz na Concurrency in Swing więcej szczegółów

enter image description here

import java.awt.BorderLayout; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.io.File; 
import java.io.IOException; 
import java.io.InputStream; 
import java.util.List; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JTextArea; 
import javax.swing.SwingWorker; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class PBDemo { 

    public static void main(String[] args) throws Exception { 
     new PBDemo(); 
    } 

    public PBDemo() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
       } 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.setLayout(new BorderLayout()); 
       frame.add(new TestPane()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class TestPane extends JPanel { 

     public TestPane() { 
      setLayout(new BorderLayout()); 
      JTextArea ta = new JTextArea(); 
      add(new JScrollPane(ta)); 

      new ProcessWorker(ta).execute(); 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      return new Dimension(200, 200); 
     } 
    } 

    public interface Consumer { 
     public void consume(String value);    
    } 

    public class ProcessWorker extends SwingWorker<Integer, String> implements Consumer { 

     private JTextArea textArea; 

     public ProcessWorker(JTextArea textArea) { 
      this.textArea = textArea; 
     } 

     @Override 
     protected void process(List<String> chunks) { 
      for (String value : chunks) { 
       textArea.append(value); 
      } 
     } 

     @Override 
     protected Integer doInBackground() throws Exception { 
      // Forced delay to allow the screen to update 
      Thread.sleep(5000); 
      publish("Starting...\n"); 
      int exitCode = 0; 
      ProcessBuilder pb = new ProcessBuilder("java.exe", "-jar", "HelloWorld.jar"); 
      pb.directory(new File("C:\\DevWork\\personal\\java\\projects\\wip\\StackOverflow\\HelloWorld\\dist")); 
      pb.redirectError(); 
      try { 
       Process pro = pb.start(); 
       InputConsumer ic = new InputConsumer(pro.getInputStream(), this); 
       System.out.println("...Waiting"); 
       exitCode = pro.waitFor(); 

       ic.join(); 

       System.out.println("Process exited with " + exitCode + "\n"); 

      } catch (Exception e) { 
       System.out.println("sorry" + e); 
      } 
      publish("Process exited with " + exitCode); 
      return exitCode; 
     } 

     @Override 
     public void consume(String value) { 
      publish(value); 
     } 
    } 

    public static class InputConsumer extends Thread { 

     private InputStream is; 
     private Consumer consumer; 

     public InputConsumer(InputStream is, Consumer consumer) { 
      this.is = is; 
      this.consumer = consumer; 
      start(); 
     } 

     @Override 
     public void run() { 
      try { 
       int in = -1; 
       while ((in = is.read()) != -1) { 
//     System.out.print((char) in); 
        consumer.consume(Character.toString((char)in)); 
       } 
      } catch (IOException exp) { 
       exp.printStackTrace(); 
      } 
     } 
    } 
} 
+0

Nie działa dla mnie, tak jak powiedziałem, myślę, że to ma związek z tym, że przekierowałem wyjście konsoli do JTextArea. – Ciphor

+0

Nie było żadnej wzmianki o "JTextArea"? Czy wykonujesz proces w EDT? – MadProgrammer

+0

Przepraszam, tak, zdaję sobie sprawę, że to była najważniejsza przyczyna problemu, o czym pisałem wcześniej. I jeszcze nie zakryliśmy wątków na moim kursie przepraszam>< – Ciphor

Powiązane problemy