使用ProcessBuilder,我需要能够将非ASCII参数发送到另一个Java程序。
在这种情况下,程序Abc需要通过参数向Def程序发送阿拉伯字符。我控制Abc代码,但不控制Def。
使用常规的ProcessBuilder方式不需要任何的编码,它被提到了这里,这是不可能的。Def收到问号“?”。
然而,我能够得到一些结果,但不同的编码可以用于不同的场景。
我正在尝试将所有编码发送给收件人,并比较所期望的结果。
UTF-8windows-1252、windows-1254和windows-1258windows-1252CESU-8和UTF-8ISO-8859-1ISO-2022-CN、ISO-2022-KR、ISO-8859-1、ISO-8859-15、ISO-8859-9、x-IBM1129、x-ISO-2022-CN-CNS和x-ISO-2022-CN-GB我的问题是:如何以编程方式知道使用哪种正确的编码,因为我需要一些通用的东西?
换句话说,默认字符集和找到的字符集之间的关系是什么?
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();
}
}
}
public class Def {
public static void main(String[] args) {
System.out.println(args[0]);
}
}发布于 2020-11-03 12:45:44
在引擎盖下,实际上传递的是字节,而不是字符。通常,您会期望java方法最终将字符转换为字节,从而具有允许指定字符集的重载,但是,无论出于什么原因,它在这里并不存在。
它应该如何发挥作用是这样的:
Charset.defaultCharset()将该字符串转换为字节(为什么?因为PB完全是让操作系统做事情,默认的字符集反映了操作系统的首选字符集)。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无关。
发布于 2020-11-03 13:09:35
一种可能是将字符串转换为Unicode序列字符串,然后将其传递给另一个进程,然后将其转换回常规字符串。Unicode序列的字符串将始终只包含ASCI字符。以下是它的样子:
String encoded = StringUnicodeEncoderDecoder.encodeStringToUnicodeSequence("hello أحمد"));其结果将是字符串编码将保存此值:
"\u0068\u0065\u006c\u006c\u006f\u0020\u0623\u062d\u0645\u062f"这个字符串可以安全地传递到另一个进程。在另一个过程中,您可以执行以下操作:
String originalString = StringUnicodeEncoderDecoder.decodeUnicodeSequenceToString(encodedString);其结果将是originalString现在将保持这个值:
"hello أحمد"类StringUnicodeEncoderDecoder可以在一个名为MgntUtils的开源库中找到。您可以以Maven人工制品的形式获得这个库,也可以在Github上获得它(包括源代码和JavaDoc)。JavaDoc online可获得这里
这个库和这个特定的特性被多个用户使用和很好的测试。
Disclamer:这个库是我写的
https://stackoverflow.com/questions/64662917
复制相似问题