Java进程无法从gpg.exe捕获InputStream、OutputStream
我正在尝试使用 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 --symmetry --output MTR241_20111124.htm.gpg MTR241_20111124.htm
。
有两种情况。 情况 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 和命令提示符会打印相同的消息。
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
gpg: CAST5 encrypted data
gpg: encrypted with 1 passphrase
gpg: WARNING: message was not integrity protected
到目前为止已经足够好了
Case2:当输出文件已经按照命令提示符中的预期存在时,它会询问我是否要替换。
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 在 java 程序中运行此 gpg.exe,所有这些都显示相同的结果,无法捕获该特殊情况下进程的输出流。我什至尝试编写一个 .bat 文件来运行 gpg --decrypt
但即使如此,它也无法在上述特殊情况下捕获输出流。
我认为这很重要,gpg.exe 的起源。好吧,我在便携式 git 发行版中得到了它,在 bin 文件夹中 gpg.exe 可用。
我的问题变得非常漫长和无聊,但对于那些喜欢指出错误的人来说,java代码
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 平台编写的,所以可能会有一些输入输出文件重定向,但我想了解更多关于它的根本原因,以便下次我知道什么寻找。
I am trying to decrypt using gpg.exe --passphrase-file my.passphrase --decrypt --output MTR241_20111124.htm MTR241_20111124.htm.gpg
(without --batch and --yes option). I am also providing the encryption command if anyone cares to use it for testing gpg.exe --passphrase-file ..\BE\src\my.passphrase --symmetric --output MTR241_20111124.htm.gpg MTR241_20111124.htm
.
There are two cases.
case 1: MTR241_20111124.htm file does not exist in the output dir. Both command prompt and captured output stream of exec gives same output.
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
The same messags gets printed by java exec and command prompt.
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
gpg: CAST5 encrypted data
gpg: encrypted with 1 passphrase
gpg: WARNING: message was not integrity protected
So far good enough
Case2: When the output file already exists as expected in command prompt it asked if I want to replace.
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
But this output is from java program which hangs after this first line. It does not print any line on console. If I enter 'y' in console, it does not accept the input and process. It simply hangs. I have to manually kill the process taskkill /F /IM gpg.exe only then the java console program accepts more commands and process.
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--
The normal interactive commands of course works, say for ex:
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.
So here is my question why does it fail to capture output stream of gpg only when it asks for the prompt whether to replace the existing output file.
I already tried Runtime.exec(), ProcessBuilder, Plexus-Utils, ExpectJ, Ant to run this gpg.exe inside the java program all of them are showing the same result fails to capture output stream of the process in that special case. I even tried to write a .bat file to run the gpg --decrypt
but even in that also it fails to capture output stream in above special case.
I think it matters, the origin of gpg.exe. Well I got it in portable git distribution, in the bin folder gpg.exe is available.
My question became really long and boring, but still for those who like to point out errors 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);
}
}
One last word if I use the gpg --batch
option, it no more prompts for the y/N
input, so then it runs smoothly. But I am just curious to know, why would there be this problem. Although I have a feeling that gpg.exe was originally written for Unix/Linux like platform, so there might be some input output file redirection, but I would like to know more on the root cause of it, so that next time I know what to look for.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您在终端中看到的输出是标准输出流、标准错误流和控制台的合并结果。您可以捕获标准输出和标准错误流。但您无法捕获控制台。这就是为什么 gpg 故意直接使用控制台,以防止您捕获。他们为什么这样做是有争议的。
底线:您将无法捕获直接处理控制台的程序的输入或输出流。
The output that you see in the terminal is a merged result from the standard output stream, standard error stream and console. You can capture standard output and standard error stream. But you cannot capture console. This is why gpg intentionally uses console directly, to prevent you from capturing. Why they do this is debatable.
Bottom line: you will not be able to capture Input or Output Stream of a program that deals directly with the console.