我正在创建一个子进程,并读取其输出。当子进程创建输出(cmd /c echo Hello World
)时,我的代码工作正常,但是如果进程没有创建输出(cmd /c echo Hello World > output.txt
),则ReadFile将挂起。我只是在流程终止后才开始阅读。
我做错了什么吗?无论如何使用同步模式执行此操作,还是必须使用异步模式?所有这一切都发生在一个单独的线程中,所以我不认为异步模式会给我任何好处,除非它是让这个工作的唯一方法。非常感谢!
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0);
SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0);
memset(&piProcInfo, 0, sizeof(PROCESS_INFORMATION));
memset(&siStartInfo, 0, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = g_hChildStd_OUT_Wr;
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
CreateProcess(NULL, commandWideString, NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &piProcInfo);
while(1)
{
GetExitCodeProcess(piProcInfo.hProcess, &processExitCode);
if(processExitCode != STILL_ACTIVE)
break;
else
Sleep(1);
}
*output = (char *)calloc(32, sizeof(char));
processOutputSize = 0;
while(1)
{
bSuccess = ReadFile( g_hChildStd_OUT_Rd, processOutputTemp, 32, &dwRead, NULL);
if(!bSuccess || !dwRead)
break;
memcpy(*output + processOutputSize, processOutputTemp, dwRead);
processOutputSize += dwRead;
if(dwRead == 32)
*output = (char *)realloc(*output, processOutputSize + 32);
else
{
memset(*output + processOutputSize, 0, 1);
break;
}
}
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
CloseHandle(g_hChildStd_OUT_Rd);
CloseHandle(g_hChildStd_OUT_Wr);
答案 0 :(得分:7)
您应该在读取之前关闭输出管道的写入端,正如@Marcus在评论中建议的那样。
String keys[] = keyString.split(";");
String values[] = valueString.split(";);
... probably some consistency checks that arrays have same length; and no nulls in keys
Map<String, String> map = new HashMap<>();
for (int i=0; i < keys.length; i++) {
map.put(keys[i], values[i]);
}
对我而言,这才是真正的答案。
答案 1 :(得分:4)
您将进程的输出重定向到管道,启动进程,等待它退出,然后读取输出。
问题是windows只缓存有限数量的数据。因此,您必须在进程仍在运行时读取管道,否则进程将被阻止,因为它无法再将更多数据写入管道。
答案 2 :(得分:1)
你可以在这样的循环中使用PeekNamedPipe:
for (;;)
{
DWORD bytesAvail = 0;
if (!PeekNamedPipe(stdoutPipeRead, NULL, 0, NULL, &bytesAvail, NULL)) {
std::cout << "Failed to call PeekNamedPipe" << std::endl;
}
if (bytesAvail) {
CHAR buf[BUFSIZE];
DWORD n;
BOOL success = ReadFile(stdoutPipeRead, buf, BUFSIZE, &n, NULL);
if (!success || n == 0) {
std::cout << "Failed to call ReadFile" << std::endl;
}
std::cout << std::string(buf, buf + n);
}
}