2015-12-08 6 views
3

У меня есть простая задача захвата всего вывода System.out; Однако я неудача:Java System.out не перенаправляется

public class Main { 
    ScriptEngine engine = new ScriptEngineManager().getEngineByName("js"); 
    ArrayList<String> history = new ArrayList<>(); 
    StringBuilder output = new StringBuilder(); 
    StringBuilder input = new StringBuilder(); 
    JPanel panel = new JPanel(); 
    JTextArea txt = new JTextArea(); 
    String PROMPT = "> "; 
    Runnable show = new Runnable() { 
      public void run() { 
       txt.setText(""); 
       for (String line: history) txt.append(line + "\n"); 
       txt.append(PROMPT); 
       txt.append(output.toString()); 
       txt.setCaretPosition(txt.getText().length()); 
      } 
     }; 
    PrintStream os = new PrintStream(new OutputStream() { 
      @Override 
      public void write(int b) throws IOException { 
       if (b == 13) { 
        history.add(input.toString()); 
        input = new StringBuilder(); 
        SwingUtilities.invokeLater(show); 
       } else input.append((char)b); 
      } 
     }); 
    void init(String title) { 
     panel.setLayout(new BorderLayout()); 
     txt.setLineWrap(true); 
     txt.setFont(new Font("Courier", Font.PLAIN, 16)); 
     txt.setBackground(Color.BLACK); 
     txt.setForeground(Color.GREEN); 
     txt.setCaretColor(Color.GREEN); 
     txt.setEditable(false); 
     txt.setText(PROMPT); 
     txt.addKeyListener(new KeyListener() { 
      @Override 
      public void keyTyped(KeyEvent e) { 
       if (e.getKeyChar() == '\n') { 
        System.setOut(os); 
        System.setErr(os); 
        String result = output.toString(); 
        history.add(PROMPT + result); 
        try { 
         engine.eval(result); 
        } catch (ScriptException ex) { 
         history.add(ex.toString()); 
        } 
        output = new StringBuilder(); 
       } else { 
        output.append(e.getKeyChar()); 
       } 
       SwingUtilities.invokeLater(show); 
      } 
      @Override 
      public void keyPressed(KeyEvent e) { 

      } 
      @Override 
      public void keyReleased(KeyEvent e) { 

      } 
     }); 
     panel.add(txt, BorderLayout.CENTER); 
     JFrame frame = new JFrame(title); 
     frame.setSize(650, 425); 
     frame.setContentPane(panel); 
     frame.setLocationRelativeTo(null); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setVisible(true); 
    } 
    public static void main(String args[]) { 
     new Main().init("javascript"); 
    } 
} 

Я хотел бы отметить выход я ищу приходит из чего-то вроде:

new ScriptEngineManager().getEngineByName("js").eval("print(\"test\");"); 

выхода не будет нигде, кроме нормального STDOUT А.К.А. System.out. Зачем? перенаправление вывода

ответ

2

ScriptEngine:

Чтобы перенаправить вывод скрипта сначала должны получить свой экземпляр ScriptContext, который имеет метод, называемый setWriter (Writer). Это устанавливает вывод ScriptEngine.

Для этого вам сначала нужен Писатель. Это может быть просто, как этот:

public class CaptureWriter extends Writer 
{ 

    private StringBuilder m_build; 

    public CaptureWriter(StringBuilder build) 
    { 
     m_build = build; 
    } 

    @Override 
    public void write(char[] cbuf, int off, int len) throws IOException 
    { 
     m_build.insert(m_build.length(), cbuf, off, len); 
    } 

    @Override 
    public void flush() throws IOException 
    { 
    } 

    @Override 
    public void close() throws IOException 
    { 
    } 

} 

Это записывает все входные данные в StringBuilder.

Тогда вы регистрируете его в ScriptContext

ScriptEngine engine = new ScriptEngineManager().getEngineByName("js"); 

engine.getContext().setWriter(new CaptureWriter(m_mess)); 

При выполнении этой простой программы:

StringBuilder build = new StringBuilder(); 

    ScriptEngine engine = new ScriptEngineManager().getEngineByName("js"); 

    engine.getContext().setWriter(new CaptureWriter(build)); 

    try 
    { 
     engine.eval("print(\"Hello\")"); 
     engine.eval("print(\"World\")"); 
     engine.eval("print(\"You\")"); 
     engine.eval("print(\"There\")"); 
    } catch(ScriptException e) 
    { 
     e.printStackTrace(); 
    } 

    System.out.println(build); 

Выход буферизированная выход сценария:

Hello 
World 
You 
There 

Вы можете конечно, что-нибудь вписывает в метод записи реализации Writer, это просто пример.

System.out Перенаправление:

Для захвата вывода System.out вы должны сделать свою собственную реализацию PrintStream, это может быть очень простым, как:

public class Capture extends PrintStream 
{ 

    private StringBuilder m_build; 

    public Capture(OutputStream out, StringBuilder build) 
    { 
     super(out); 

     m_build = build; 
    } 

    public void println(String s) 
    { 
     super.println(s); 

     m_build.append(s + "\n"); 
    } 

} 

Затем вам нужно зарегистрировать его в среда выполнения:

StringBuilder build = new StringBuilder(); 

System.setOut(new Capture(System.out, build)); 

Тогда каждый раз, когда System.out.println называется он работает как наиважнейшей PrintStream должно и сообщение будет записано в пров встроенный StringBuilder.

Чтобы записать другие сообщения, вам необходимо переопределить другие методы.

+0

Я сожалею, но это не решает мою проблему. – motoku

+0

Какая часть проблемы заключается не в решении? Он ловит вывод System.out и позволяет вам делать что-либо с ним. – tim4242

+0

Проблема, описанная в моем вопросе получения результата «ScriptEngine» – motoku

0

Вы можете захватить System.out быть обеспечивая PrintStream, что вы контролируете ... попробовать что-то вроде этого

ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
PrintStream ps = new PrintStream(baos); 
PrintStream old = System.out; 
System.setOut(ps); 
System.out.println("This will be captured :P"); 
System.out.flush(); 
System.setOut(old); 
System.out.println("He is what was captured : " + baos.toString()); 
Смежные вопросы