Перенаправление выходного потока канала jsch exec в файл с помощью setOutputStream не работает


Я использую канал jsch exec для входа на несколько серверов и запуска нескольких команд. Затем мне нужно захватить выходные данные и сохранить их в файле под названием log. По какой-то странной причине файл остается пустым после выполнения.

try (OutputStream log = new BufferedOutputStream(new FileOutputStream(outputFilePath))) {
    ArrayList<String> lists = new ArrayList<String>();
    lists.add("hostname");
    lists.add("df -l");
    String host ="localhost";

    JSch jsch = new JSch();
    try {
        String user = "user";
        String password = "pass";
        Session session = jsch.getSession(user, host, 22);
        session.setPassword(password);
        session.setConfig(getProperties());
        session.setTimeout(20 * 1000);
        System.out.println(session.getTimeout());
        session.connect();
        if (session.isConnected()) {
            System.out.println(host + " Session Established ");
        }

        for (String elem : lists) {
            Channel channel = session.openChannel("exec");
            channel.setOutputStream(log);

            ((ChannelExec) channel).setCommand(elem);

            channel.setInputStream(null);

            ((ChannelExec) channel).setErrStream(System.err);

            InputStream in = channel.getInputStream();

            channel.connect();

            byte[] tmp = new byte[1024];
            while (true) {
                while (in.available() > 0) {
                    int i = in.read(tmp, 0, 1024);
                    if (i < 0) {
                        break;
                    }
                    System.out.print(new String(tmp, 0, i));
                }
                if (channel.isClosed()) {
                    if (in.available() > 0) {
                        continue;
                    }
                    System.out.println("exit-status: " + channel.getExitStatus());
                    break;
                }
                try {
                    Thread.sleep(1000);
                } catch (Exception ee) {
                }
            }
            channel.disconnect();
        }

        session.disconnect();

Программа отображает выходные данные через консоль IDE, но выходной файл создается, но остается пустым.

Затем я установил system.setOut в файл, это помешало консоли отображать больше данных, но файл output.txt остается пустым.

System.setOut(new PrintStream(new BufferedOutputStream(new FileOutputStream("output.txt"))));
1 2

1 ответ:

Это потому, что getInputStream переопределяет вызов setOutputStream.

Смотрите, как эти методы реализованы в JSch (оба заканчиваются вызовом io.setOutputStream):

public void setOutputStream(OutputStream out){
  io.setOutputStream(out, false);
}

public InputStream getInputStream() throws IOException {
  int max_input_buffer_size = 32*1024;
  try {
    max_input_buffer_size =
      Integer.parseInt(getSession().getConfig("max_input_buffer_size"));
  }
  catch(Exception e){}
  PipedInputStream in =
    new MyPipedInputStream(
                           32*1024,  // this value should be customizable.
                           max_input_buffer_size
                           );
  boolean resizable = 32*1024<max_input_buffer_size;
  io.setOutputStream(new PassiveOutputStream(in, resizable), false);
  return in;
}

Я предполагаю, что вам на самом деле не нужен этот выходной блок чтения, основанный на InputStream in. Просто удалите его, и запись файла журнала должна начать работать.


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

Использовать переопределение из аргумента setOutputStream с аргументом dontclose:

public void setOutputStream(OutputStream out, boolean dontclose)

Вот так:

channel.setOutputStream(log, true);