在 Java 中解析 Windows 任务列表输出
Parsing Windows tasklist output in Java
我正在尝试在我的机器上构建进程数组 运行;为此,我一直在尝试使用以下两个命令:
tasklist /fo csv /nh # For a CSV output
tasklist /nh # For a non-CSV output
我遇到的问题是无法正确解析输出。
第一个场景
我有这样一行:
"wininit.exe","584","Services","0","5,248 K"
我曾尝试使用 "".split(",")
进行解析,但是当涉及到进程内存使用时,这会失败 - 数字字段中的逗号将导致一个额外的字段。
第二种情况
没有非 CSV 输出,我有这样一行:
wininit.exe 584 Services 0 5,248 K
我正在尝试使用 "".split("\s+")
进行解析,但是这个现在在 System Idle Process
之类的进程或任何其他可执行文件名称中带有 space 的进程上失败。
How can I parse either of these output such that the same split index will always contain the correct data column?
您应该使用 StringTokenizer class 而不是拆分。您使用 "
定界符并期望返回定界符。然后您可以使用该定界符来提供字段分隔。例如,
StringTokenizer st = new StringTokenizer(input, "\"", true);
State state = NONE;
while (st.hasMoreTokens()) {
String t = st.nextToken();
switch(state) {
case NONE:
if ("\"".equals(t)) {
state = BEGIN;
}
// skip the ,
break;
case BEGIN:
// Store t in which entry it correspond to.
state = END;
break;
case END:
state = NONE;
break;
}
}
每个令牌都将存储在其各自的数据集中,然后您可以为每个进程处理该信息。
试过这个似乎有效。
public void parse(){
try {
Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec("tasklist -fo csv /nh");
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(proc.getInputStream()));
String line = "";
while ((line = stdInput.readLine()) != null) {
System.out.println();
for (String column: line.split("\"")){
if (!column.equals(",")&& !column.equals("")){
System.out.print("["+column+"]");
}
}
}
}catch (Exception e){
e.printStackTrace();
}
}
要解析一个字符串,总是喜欢最严格的格式。在这种情况下,CSV。这样,您可以使用包含五个组的正则表达式处理每一行:
private final Pattern pattern = Pattern
.compile("\\"([^\\"]*)\\",\\"([^\\"]*)\\",\\"([^\\"]*)\\",\\"([^\\"]*)\\",\\"([^\\"]*)\\"");
private void parseLine(String line) {
Matcher matcher = pattern.matcher(line);
if (!matcher.find()) {
throw new IllegalArgumentException("invalid format");
}
String name = matcher.group(1);
int pid = Integer.parseInt(matcher.group(2));
String sessionName = matcher.group(3);
String sessionId = matcher.group(4);
String memUsage = matcher.group(5);
System.out.println(name + ":" + pid + ":" + memUsage);
}
我正在尝试在我的机器上构建进程数组 运行;为此,我一直在尝试使用以下两个命令:
tasklist /fo csv /nh # For a CSV output
tasklist /nh # For a non-CSV output
我遇到的问题是无法正确解析输出。
第一个场景
我有这样一行:
"wininit.exe","584","Services","0","5,248 K"
我曾尝试使用 "".split(",")
进行解析,但是当涉及到进程内存使用时,这会失败 - 数字字段中的逗号将导致一个额外的字段。
第二种情况
没有非 CSV 输出,我有这样一行:
wininit.exe 584 Services 0 5,248 K
我正在尝试使用 "".split("\s+")
进行解析,但是这个现在在 System Idle Process
之类的进程或任何其他可执行文件名称中带有 space 的进程上失败。
How can I parse either of these output such that the same split index will always contain the correct data column?
您应该使用 StringTokenizer class 而不是拆分。您使用 "
定界符并期望返回定界符。然后您可以使用该定界符来提供字段分隔。例如,
StringTokenizer st = new StringTokenizer(input, "\"", true);
State state = NONE;
while (st.hasMoreTokens()) {
String t = st.nextToken();
switch(state) {
case NONE:
if ("\"".equals(t)) {
state = BEGIN;
}
// skip the ,
break;
case BEGIN:
// Store t in which entry it correspond to.
state = END;
break;
case END:
state = NONE;
break;
}
}
每个令牌都将存储在其各自的数据集中,然后您可以为每个进程处理该信息。
试过这个似乎有效。
public void parse(){
try {
Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec("tasklist -fo csv /nh");
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(proc.getInputStream()));
String line = "";
while ((line = stdInput.readLine()) != null) {
System.out.println();
for (String column: line.split("\"")){
if (!column.equals(",")&& !column.equals("")){
System.out.print("["+column+"]");
}
}
}
}catch (Exception e){
e.printStackTrace();
}
}
要解析一个字符串,总是喜欢最严格的格式。在这种情况下,CSV。这样,您可以使用包含五个组的正则表达式处理每一行:
private final Pattern pattern = Pattern
.compile("\\"([^\\"]*)\\",\\"([^\\"]*)\\",\\"([^\\"]*)\\",\\"([^\\"]*)\\",\\"([^\\"]*)\\"");
private void parseLine(String line) {
Matcher matcher = pattern.matcher(line);
if (!matcher.find()) {
throw new IllegalArgumentException("invalid format");
}
String name = matcher.group(1);
int pid = Integer.parseInt(matcher.group(2));
String sessionName = matcher.group(3);
String sessionId = matcher.group(4);
String memUsage = matcher.group(5);
System.out.println(name + ":" + pid + ":" + memUsage);
}