使用ProcessBuilder
,我需要能够将非ASCII参数发送到另一个Java程序。
在这种情况下,程序Abc
需要通过参数向Def
程序发送阿拉伯字符。我控制Abc
代码,但不控制Def
。
使用常规的ProcessBuilder
方式不需要任何的编码,它被提到了这里,这是不可能的。Def
收到问号“?”。
然而,我能够得到一些结果,但不同的编码可以用于不同的场景。
我正在尝试将所有编码发送给收件人,并比较所期望的结果。
UTF-8
windows-1252
、windows-1254
和windows-1258
windows-1252
CESU-8
和UTF-8
ISO-8859-1
ISO-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
复制相似问题