Process.getInputStream()使用哪种编码?

时间:2011-12-06 10:20:18

标签: java character-encoding

在Java程序中,我通过Process生成一个新的ProcessBuilder

args[0] = directory.getAbsolutePath() + File.separator + program;
ProcessBuilder pb = new ProcessBuilder(args);
pb.directory(directory);
final Process process = pb.start();

然后,我使用新的Thread

读取过程标准输出
new Thread() {
    public void run() {
        BufferedReader reader = new BufferedReader(
            new InputStreamReader(process.getInputStream()));
        String line = "";
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
    }
}.start();

但是,当该过程输出非ASCII字符(例如'é')时,line会改为字符'\uFFFD'

InputStream返回的getInputStream中的编码是什么(我的平台是欧洲的Windows)?

如何更改内容以使line包含预期数据(即'\u00E9'的{​​{1}})?

修改:我试过'é'new InputStreamReader(...,"UTF-8")变为é

8 个答案:

答案 0 :(得分:9)

InputStream是二进制流,因此没有编码。创建Reader时,您需要知道要使用的字符编码,这取决于您调用的程序产生的内容(Java不会以任何方式转换它)。

如果没有为InputStreamReader指定任何内容,它将使用平台默认编码,这可能不合适。 another constructor允许您指定编码。

如果你知道要使用什么编码(你真的必须知道):

new InputStreamReader(process.getInputStream(), "UTF-8") // for example

答案 1 :(得分:5)

有趣的是,在Windows上运行时:

ProcessBuilder pb = new ProcessBuilder("cmd", "/c dir");
Process process = pb.start();

然后CP437代码页适用于

new InputStreamReader(process.getInputStream(), "CP437");

答案 2 :(得分:3)

据我所知,操作系统流是字节流,这里没有字符。 InputStreamReader构造函数使用jvm默认字符集java.nio.charset.Charset#defaultCharset(),您可以使用另一个构造函数来显式指定字符集。

答案 3 :(得分:2)

根据http://www.fileformat.info/info/unicode/char/e9/index.htm'\ uFFFD'是字符'é'的unicode代码。它实际上意味着您正在正确地读取流。你的问题是书面形式。

默认情况下,Windows控制台不支持unicode。所以,如果你想测试你的代码打开文件并在那里写你的流。但是不要忘记设置编码UTF-8

答案 4 :(得分:1)

科学

在Windows上,这非常有效:

private static final Charset CONSOLE_ENCODING;
static {
    Charset enc = Charset.defaultCharset();
    try {
        String example = "äöüßДŹす";
        String command = File.separatorChar == '/' ? "echo " + example : "cmd.exe /c echo " + example;
        Process exec = Runtime.getRuntime().exec(command);
        InputStream inputStream = exec.getInputStream();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        while (exec.isAlive()) {
            Thread.sleep(100);
        }
        byte[] buff = new byte[inputStream.available()];
        if (buff.length > 0) {
            int count = inputStream.read(buff);
            baos.write(buff, 0, count);
        }

        byte[] array = baos.toByteArray();
        for (Charset charset : Charset.availableCharsets().values()) {
            String s = new String(array, charset);
            if (s.equals(example)) {
                enc = charset;
                break;
            }
        }
    } catch (InterruptedException e) {
        throw new Error("Could not determine console charset.", e);
    } catch (IOException e) {
        throw new Error("Could not determine console charset.", e);
    }
    CONSOLE_ENCODING = enc;
}

根据规范:没有提示jvm的运行时编码更改。我们不能确保编码在运行时不会更改,并且在更改后字符集仍然正确。

答案 5 :(得分:1)

如果像我一样,如果您想对所有输入/输出使用哪种编码,则可以在对某些(并非全部)CreateReader方法的Java API调用中对它进行编码,其他一些答案也指出了这一点。

但这会在源代码中对其进行硬编码,这可能会也可能不会。

在阅读this answer之后,我发现了一种更好的方法,该方法表明您可以在JVM启动之前将编码设置为所需的值。

java -Dfile.encoding=ISO-8859-1 ...

答案 6 :(得分:0)

我把它作为评论,但我看到之后有一个答案,所以现在可能是多余的:)

BufferedReader br = new BufferedReader(
    new InputStreamReader(conn.getInputStream(), "UTF-8"));

答案 7 :(得分:0)

在此用途中使用commons-lang jar文件 - StringEscapeUtils.escapeHtml

BufferedReader br = new BufferedReader(
    new InputStreamReader(StringEscapeUtils.escapeHtml(conn.getInputStream()));