当一个应用程序写好后,为了调试或其它需要我们往往需要重新定向程序的输入输出,如:将程序的调试信息从控制台记入文件已备分析等。在不改变已有程序的情况下,无论是Windows应用程序还是Java应用程序,都提供了解决办法,都是以将待重定向的应用程序做为子应用程序启动来解决的。下面将分别介绍两种应用程序如何重定向输入输出。
Windows应用程序
Windows中启动程序的标准API是CreateProcess,该API有一个LPSTARTUPINFO类型的参数,该结构描述如下:
typedef struct _STARTUPINFO {
DWORD cb;
LPTSTR lpReserved;
LPTSTR lpDesktop;
LPTSTR lpTitle;
DWORD dwX;
DWORD dwY;
DWORD dwXSize;
DWORD dwYSize;
DWORD dwXCountChars;
DWORD dwYCountChars;
DWORD dwFillAttribute;
DWORD dwFlags;
WORD wShowWindow;
WORD cbReserved2;
LPBYTE lpReserved2;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
} STARTUPINFO, *LPSTARTUPINFO;
其中的hStdInput指应用程序使用的标准输入句柄,hStdOutput指应用程序的标准输出句柄,hStdError指应用程序的标准错误句柄。现在我们就可以通过指明这些参数将应用程序的标准输入输出指向我们需要的任何一个地方了。例如我想将输出重定向到文件debug.txt,下面是代码片断:
Handle hOutput = CreateFile(“debug.txt”,…);
STARTUPINFO si;
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdOutput = hOutput;
Handle hProcess = CreateProcess(“app.exe”,…,&si,…);
且记,编程时一定要为dwFlags参数赋值。
Java应用程序
Java应用程序有一个Process类,概念上等同于CreateProcess返回的进程句柄。该类中有三个方法
getErrorStream
()
、getInputStream()和getOutputStream()。这三个方法的含义分别为获得进程的错误流,获得进程的输入流和获得进程的输出流。但需要注意的是,这里获得的进程的输入流其实是与子进程的输出流连在一起的,而输出流是与子进程的输入流连在一起的。这就意味着,我们从输入流中读到的数据其实是进程的输出,而我们向输出流中写入地数据实际会被程序的输入流接收到。下面给出了一个把子程序的输出捕获后,前面加上了程序名后重新输出的示例:
public class OutputConsole {
public static void main(String[] args) {
String cmd[] = {"java","-classpath","./bin","test.OutputApp"};
Runtime run = Runtime.getRuntime();
Process process = null;
BufferedReader br = null;
try {
process = (Process)run.exec(cmd);
InputStream is = process.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
String data = null;
while(true) {
data = br.readLine();
if (data == null)
break;
System.out.println("OutputApp:"+ data);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
br.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
process.destroy();
}
}
}