首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >ProcessBuilder参数的哪种编码

ProcessBuilder参数的哪种编码
EN

Stack Overflow用户
提问于 2020-11-03 12:31:54
回答 2查看 265关注 0票数 0

使用ProcessBuilder,我需要能够将非ASCII参数发送到另一个Java程序。

在这种情况下,程序Abc需要通过参数向Def程序发送阿拉伯字符。我控制Abc代码,但不控制Def

使用常规的ProcessBuilder方式不需要任何的编码,它被提到了这里,这是不可能的。Def收到问号“?”。

然而,我能够得到一些结果,但不同的编码可以用于不同的场景。

我正在尝试将所有编码发送给收件人,并比较所期望的结果。

  1. Windows,IntelliJ控制台:
    1. 默认字符集:UTF-8
    2. 找到字符集:windows-1252windows-1254windows-1258

  2. 窗口,命令提示符:
    1. 默认字符集:windows-1252
    2. 找到字符集:CESU-8UTF-8

  3. 命令提示符:
    1. 默认字符集:ISO-8859-1
    2. 查找字符集:ISO-2022-CNISO-2022-KRISO-8859-1ISO-8859-15ISO-8859-9x-IBM1129x-ISO-2022-CN-CNSx-ISO-2022-CN-GB

我的问题是:如何以编程方式知道使用哪种正确的编码,因为我需要一些通用的东西?

换句话说,默认字符集和找到的字符集之间的关系是什么?

代码语言:javascript
复制
public class Abc {

  private static final Path PATH = Paths.get("."); // With maven: ./target/classes

  public static void main(String[] args) throws Exception {
    var string = "hello أحمد";
    var bytes = string.getBytes();

    System.out.println("Original string: " + string);
    System.out.println("Default charset: " + Charset.defaultCharset());

    for (var c : Charset.availableCharsets().values()) {
      var newString = new String(bytes, c);

      var process = new ProcessBuilder().command("java", "-cp",
              PATH.toAbsolutePath().toString(),
              "Def", newString).start();
      process.waitFor();

      var output = asString(process.getInputStream());
      if (output.contains(string)) {
        System.out.println("Found " + c + " " + output);
      }
    }
  }

  private static String asString(InputStream is) throws IOException {
    try (var reader = new BufferedReader(new InputStreamReader(is))) {
      var builder = new StringBuilder();
      String line;
      while ((line = reader.readLine()) != null) {
        if (builder.length() != 0) {
          builder.append(System.lineSeparator());
        }
        builder.append(line);
      }
      return builder.toString();
    }
  }
}

代码语言:javascript
复制
public class Def {
  public static void main(String[] args) {
    System.out.println(args[0]);
  }
}
EN

回答 2

Stack Overflow用户

发布于 2020-11-03 12:45:44

在引擎盖下,实际上传递的是字节,而不是字符。通常,您会期望java方法最终将字符转换为字节,从而具有允许指定字符集的重载,但是,无论出于什么原因,它在这里并不存在。

它应该如何发挥作用是这样的:

  • 将字符串传递给ProcessBuilder
  • PB将使用Charset.defaultCharset()将该字符串转换为字节(为什么?因为PB完全是让操作系统做事情,默认的字符集反映了操作系统的首选字符集)。
  • 然后将这些字节输入到进程中。
  • 进程开始了。如果是java,而且我们在psv main(String[] args)中讨论的是args,则同样是相反的操作: Java获取字节并通过Charset.defaultCharset()将它们转换回字符。

这确实显示了一个直接的问题:如果默认的字符集不能表示某个字符,那么理论上您就是运气不好的。

这强烈地表明,使用java激发java.exe通常意味着您可以传递您想要的任何内容(除非所涉及的字符在系统的字符集中无法表示)。

你的代码很奇怪。特别是,这一行是问题所在:

var bytes = string.getBytes();

这是string.getBytes(Charset.defaultCharset())的缩写。现在,在提供的字符集中有您的字节。

var newString = new String(bytes, c);

现在你把这些字节转换成一个字符串,使用一个完全不同的字符集。我不知道你想用这个实现什么。纯粹的高脚杯就会出来。

换句话说,默认字符集和找到的字符集之间的关系是什么?

你说“找到的”是什么意思?字符串“找到的字符集”在代码中没有出现。如果您的意思是:Charset.availableCharsets()返回的是什么--根本就没有关系。availableCharsets与ProcessBuilder无关。

票数 3
EN

Stack Overflow用户

发布于 2020-11-03 13:09:35

一种可能是将字符串转换为Unicode序列字符串,然后将其传递给另一个进程,然后将其转换回常规字符串。Unicode序列的字符串将始终只包含ASCI字符。以下是它的样子:

代码语言:javascript
复制
String encoded = StringUnicodeEncoderDecoder.encodeStringToUnicodeSequence("hello أحمد"));

其结果将是字符串编码将保存此值:

代码语言:javascript
复制
"\u0068\u0065\u006c\u006c\u006f\u0020\u0623\u062d\u0645\u062f"

这个字符串可以安全地传递到另一个进程。在另一个过程中,您可以执行以下操作:

代码语言:javascript
复制
String originalString = StringUnicodeEncoderDecoder.decodeUnicodeSequenceToString(encodedString);

其结果将是originalString现在将保持这个值:

代码语言:javascript
复制
"hello أحمد"

StringUnicodeEncoderDecoder可以在一个名为MgntUtils的开源库中找到。您可以以Maven人工制品的形式获得这个库,也可以在Github上获得它(包括源代码和JavaDoc)。JavaDoc online可获得这里

这个库和这个特定的特性被多个用户使用和很好的测试。

Disclamer:这个库是我写的

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64662917

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档