Процесс Java не может захватить InputStream, OutputStream из gpg.exe - PullRequest
3 голосов
/ 27 ноября 2011

Я пытаюсь расшифровать, используя gpg.exe --passphrase-file my.passphrase --decrypt --output MTR241_20111124.htm MTR241_20111124.htm.gpg (без параметров --batch и --yes).Я также предоставляю команду шифрования, если кто-то захочет использовать ее для тестирования gpg.exe --passphrase-file ..\BE\src\my.passphrase --symmetric --output MTR241_20111124.htm.gpg MTR241_20111124.htm.

Есть два случая.case 1: файл MTR241_20111124.htm не существует в выходном каталоге.И командная строка, и захваченный поток вывода exec выдают одинаковые выходные данные.

C:\Eclipse\workspace2\sync_inbox>gpg.exe  --passphrase-file ..\BE\src\my.passphrase --decrypt --output MTR241_20111124.htm MTR241_20111124.htm.gpg
Reading passphrase from file descriptor 3
gpg: CAST5 encrypted data
gpg: encrypted with 1 passphrase
gpg: WARNING: message was not integrity protected

Одни и те же сообщения печатаются через java exec и командную строку.

Случай 2: Когда выходной файл уже существует, как и ожидалось, в командной строке он спросил, хочу ли я заменить.

C:\Eclipse\workspace2\sync_inbox>gpg.exe  --passphrase-file ..\BE\src\my.passphrase --decrypt --output MTR241_20111124.htm MTR241_20111124.htm.gpg
Reading passphrase from file descriptor 3
gpg: CAST5 encrypted data
gpg: encrypted with 1 passphrase
File `MTR241_20111124.htm' exists. Overwrite? (y/N) y
gpg: WARNING: message was not integrity protected

Но этот вывод получен из Java-программы, которая зависает после этой первой строки.Он не печатает ни одной строки на консоли.Если я ввожу 'y' в консоли, он не принимает ввод и обработку.Это просто висит.Я должен вручную убить процесс taskkill / F / IM gpg.exe только тогда, когда консольная программа java принимает больше команд и процессов.

C:\Eclipse\workspace2\sync_inbox>gpg.exe  --passphrase-file ..\BE\src\my.passphrase --decrypt --output MTR241_20111124.htm MTR241_20111124.htm.gpg
inp>gpg.exe  --passphrase-file ..\BE\src\my.passphrase --decrypt --output MTR241_20111124.htm MTR241_20111124.htm.gpg
gpg.exe  --passphrase-file ..\BE\src\my.passphrase --decrypt --output MTR241_20111124.htm MTR241_20111124.htm.gpg
    --hangs here-- 

Обычные интерактивные команды, конечно, работают, например, для:

F:\eclipse\workspace\HTMLProcessor\BEQuery>copy hello.txt world.txt
inp>copy hello.txt world.txt
copy hello.txt world.txt
Overwrite world.txt? (Yes/No/All): y
inp>y
y
        1 file(s) copied.

Итак, вот мой вопрос, почему он не может захватить поток вывода gpg, только когда он запрашивает подсказку, заменять ли существующий файл вывода.

Я уже пробовал Runtime.exec (), ProcessBuilder, Plexus-Utils, ExpectJ, Ant для запуска этого gpg.exe внутри Java-программы. Все они показывают, что один и тот же результат не может захватить поток вывода процесса в этом особом случае.Я даже пытался написать файл .bat для запуска gpg --decrypt, но даже в этом случае он не может захватить поток вывода в вышеупомянутом особом случае.

Я думаю, что это имеет значение, происхождение gpg.exe.Ну, я получил это в портативном дистрибутиве git, в папке bin доступен gpg.exe.

Мой вопрос стал действительно длинным и скучным, но все же для тех, кто любит указывать на ошибки java code

package com.ycs.ezlink.scheduler.cmd;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import org.apache.log4j.Logger;

public class CmdRunner {
    private static Logger logger = Logger.getLogger(CmdRunner.class);

    static class StreamGobbler extends Thread
    {
        InputStream is;
        String type;

        StreamGobbler(InputStream is, String type)
        {
            this.is = is;
            this.type = type;
        }

        public void run() {
            try {
                System.out.println("in run!");
                    System.out.println(type);
                    final byte[] buffer = new byte[1];
                    for (int length = 0; (length = is.read(buffer)) != -1;) {
                        System.out.write(buffer, 0, length);
                    }
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }
        }
    }

    public static int process(String cmd){
        int exitVal = 0; 
        try {
            Runtime rt = Runtime.getRuntime();
             Process proc = rt.exec(cmd);
             // any error message?
             StreamGobbler errorGobbler = new 
                 StreamGobbler(proc.getErrorStream(), "ERROR");            

             // any output?
             StreamGobbler outputGobbler = new 
                 StreamGobbler(proc.getInputStream(), "OUTPUT");

             // kick them off
             errorGobbler.start();
             outputGobbler.start();

             // any error???
             System.out.println("Waiting for cmd process to complete " );
            exitVal = proc.waitFor();
             System.out.println("ExitValue: " + exitVal);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }    
        return exitVal;
    }

    public static void main(String[] a) throws IOException, InterruptedException, TimeoutException, ExpectJException {
        String gzipCmd = "gpg.exe  --passphrase-file C:/Eclipse/workspace2/BE/src/my.passphrase --decrypt --output C:/Eclipse/workspace2/sync_inbox/MTR241_20111124.htm C:/Eclipse/workspace2/sync_inbox/MTR241_20111124.htm.gpg";  
        //CmdRunner.process(gzipCmd); ///--fails
        //ProcessBuilder pb = new ProcessBuilder("gpg", "--passphrase-file", "C:/Eclipse/workspace2/BE/src/my.passphrase",
        "--decrypt","--output","C:/Eclipse/workspace2/sync_inbox/MTR241_20111124.htm",
        "C:/Eclipse/workspace2/sync_inbox/MTR241_20111124.htm.gpg"); ///--fails
        ProcessBuilder pb = new ProcessBuilder ("cmd");
        pb.redirectErrorStream(true);
        Process process = pb.start();
        OutputStream stdin = process.getOutputStream ();
        InputStream stderr = process.getErrorStream ();
        InputStream stdout = process.getInputStream ();
         StreamGobbler errorGobbler = new StreamGobbler(stderr, "ERROR");            
         errorGobbler.start();
         StreamGobbler stdoutGobbler = new StreamGobbler(stdout, "DEBUG");            
         stdoutGobbler.start();

         BufferedReader scan = new BufferedReader(new InputStreamReader(System.in));
         String line;
         while ((line = scan.readLine())!= null) {
                String input = line;
                System.out.println("inp>"+input);
                if (input.trim().equals("exit")) {
                    stdin.write("exit\r\n".getBytes()); 
                    stdin.flush();
                    break;
                } else {
                     stdin.write((input+"\r\n").getBytes());
                     stdin.flush();
                }
            }
         System.out.println("exited..");
        int returnCode  = process.waitFor();
        System.out.println(returnCode);
    }
}

Последнее слово, если я использую опцию gpg --batch, он больше не запрашивает ввод y/N, поэтому он работает гладко.Но мне просто любопытно узнать, с чего бы возникла эта проблема.Хотя у меня есть ощущение, что gpg.exe изначально был написан для Unix / Linux-подобной платформы, поэтому может быть некоторое перенаправление входного выходного файла, но я хотел бы узнать больше об основной причине этого, чтобы в следующий раз я знал, чтоискать.

1 Ответ

2 голосов
/ 09 февраля 2012

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

1004 * Нижняя строка:.. Вы не сможете захватить входной или выходной поток программы, которая имеет дело непосредственно с консоли
...