为什么要从Java中的Windows命令行获取\r\r\n(CR LF)?

为什么要从Java中的Windows命令行获取\r\r\n(CR LF)?,java,windows,cmd,Java,Windows,Cmd,我正在用Java运行这个: Runtime.getRuntime().exec("wmic bios get SerialNumber"); 当我读取该命令的输出时,行分隔符不是预期的\r\n,而是\r\n。cmd上该命令的输出如下所示: C:\Users\pupeno>wmic bios get SerialNumber SerialNumber System Serial Number C:\Users\pupeno> ==================== Seria

我正在用Java运行这个:

Runtime.getRuntime().exec("wmic bios get SerialNumber");
当我读取该命令的输出时,行分隔符不是预期的
\r\n
,而是
\r\n
cmd
上该命令的输出如下所示:

C:\Users\pupeno>wmic bios get SerialNumber
SerialNumber
System Serial Number


C:\Users\pupeno>
====================
SerialNumber          

System Serial Number  



====================
try (InputStreamReader inputStreamReader = new InputStreamReader(p.getInputStream())) {
    int c;
    while ((c = inputStreamReader.read()) != -1) {
        String ch = String.valueOf((char) c);
        switch(c) {
            case 10:
                ch = "LF";
                break;
            case 13:
                ch = "CR";
                break;
            case 32:
                ch = "Space";
                break;

        }
        System.out.printf("%3d - %s%n", c, ch);
    }
}
如果我使用
BufferedReader
读取输出:

System.out.println("====================");
BufferedReader output = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = output.readLine()) != null) {
     System.out.println(line);
}
System.out.println("====================");
看起来是这样的:

C:\Users\pupeno>wmic bios get SerialNumber
SerialNumber
System Serial Number


C:\Users\pupeno>
====================
SerialNumber          

System Serial Number  



====================
try (InputStreamReader inputStreamReader = new InputStreamReader(p.getInputStream())) {
    int c;
    while ((c = inputStreamReader.read()) != -1) {
        String ch = String.valueOf((char) c);
        switch(c) {
            case 10:
                ch = "LF";
                break;
            case 13:
                ch = "CR";
                break;
            case 32:
                ch = "Space";
                break;

        }
        System.out.printf("%3d - %s%n", c, ch);
    }
}
正如你所看到的,我每行得到一个额外的空行。通过直接从
InputStreamReader
中读取它进行调查,如下所示:

C:\Users\pupeno>wmic bios get SerialNumber
SerialNumber
System Serial Number


C:\Users\pupeno>
====================
SerialNumber          

System Serial Number  



====================
try (InputStreamReader inputStreamReader = new InputStreamReader(p.getInputStream())) {
    int c;
    while ((c = inputStreamReader.read()) != -1) {
        String ch = String.valueOf((char) c);
        switch(c) {
            case 10:
                ch = "LF";
                break;
            case 13:
                ch = "CR";
                break;
            case 32:
                ch = "Space";
                break;

        }
        System.out.printf("%3d - %s%n", c, ch);
    }
}
我得到这个输出:

 83 - S
101 - e
114 - r
105 - i
 97 - a
108 - l
 78 - N
117 - u
109 - m
 98 - b
101 - e
114 - r
 32 - Space
 32 - Space
 32 - Space
 32 - Space
 32 - Space
 32 - Space
 32 - Space
 32 - Space
 32 - Space
 32 - Space
 13 - CR
 13 - CR
 10 - LF
 83 - S
121 - y
115 - s
116 - t
101 - e
109 - m
 32 - Space
 83 - S
101 - e
114 - r
105 - i
 97 - a
108 - l
 32 - Space
 78 - N
117 - u
109 - m
 98 - b
101 - e
114 - r
 32 - Space
 32 - Space
 13 - CR
 13 - CR
 10 - LF
 13 - CR
 13 - CR
 10 - LF

知道为什么会这样吗?所有Windows计算机都会这样吗?

也许使用PowerShell会使这变得更容易一些

Runtime.getRuntime().exec("powershell.exe -NoLogo -NoProfile -Command (Get-CimInstance -ClassName CIM_BIOSElement).SerialNumber")
一个完整的计划

import java.io.*;

public class t2 {
    public static void main( String[] args ) {
        try {
            // Runtime.getRuntime().exec("wmic bios get SerialNumber");
            Process p = Runtime.getRuntime().exec("powershell.exe -NoLogo -NoProfile -Command (Get-CimInstance -ClassName CIM_BIOSElement).SerialNumber");

            BufferedReader output = new BufferedReader(new InputStreamReader(p.getInputStream()));
            String line;
            while ((line = output.readLine()) != null) {
                 System.out.println(line);
            }
        }
        catch (Throwable t) {
        }
    }
}
这很奇怪

如果从终端运行
wmic
命令并重定向到文件,则会得到
\r\n
。如果通过Java进程运行它,则会得到
\r\n

如果您直接使用
InputStream
,而不使用
InputStreamReader
,也会发生这种情况,因此它与Unicode无关,这与您在评论中听到的相反


在一个非常快速的测试中,我找不到另一个Windows命令的行为与此类似。因此,当输出到管道时,我们似乎必须将其归结为
wmic
的一个特性。

wmic是Unicode。作为程序员,您可以直接调用它,而不需要shell。请参见此处的vbscript示例(使用相同的对象和方法)@ACatInLove好的,如果是Unicode,看起来像UTF-8。为什么UTF-8会有\r\r\n作为新线?另外,答案是.Net,这是Java。我不知道Java中存在相同的API。答案是COM,大多数语言都可以使用它,因为它是与windows交互的第二种方式。(API调用、COM调用和.NETFramework调用),并且图形的一小部分是C++(还有一个不可用的COM接口)。而且它不是UTF8,而是UTF 16。从Java访问COM是令人难以置信的复杂。为什么UTF-16使用\r\r\n?根据我所阅读的内容,UTF-16中的每个字符至少有两个字节,但我在程序中看到的是每个字符都有一个字节。我知道API可能返回UTF-16,但我从命令行得到的是看起来不像UTF-16。它看起来像ASCII(如果我们慷慨的话,也可以是UTF-8).@ACatInLove
wmic
是Unicode与它是否可以从Java访问完全无关,也与接收
\r\n
的声明问题无关。wmic显式地将CRLF添加到它所写入的字符串中。通常在C/C++中只使用LF,如果在te中打开文件,它会被标准I/O库转换为CRLFxt模式(本身不是Windows操作系统行为;它是C运行时特性)WMIC的实现是关于STDUT是磁盘文件还是管道/控制台的。当它是一个磁盘文件时,它最终使用C++流类方法<代码> cFieOutsStruts::写< /COD>基本上以二进制模式写入字符串。当它是管道或控制台时,它使用“代码> fPrPtf< /COD>”,文本模式文件描述符结束将CRLF转换为CRCRLF。此外,当写入控制台或管道时,它使用最适合的OEM编码,这将导致无法在OEM代码页中表示的字符串(一组约250个字符)混乱。这可能包括文件名、注册表项和值、用户名等。因此,通常使用wmic的最佳方法是将输出写入一个临时文件,该文件将为UTF-16,并且仅使用CRLF而不是CRLF正确结束行。