我有一个使用InputStreamReader
通过套接字接收数据的Java应用程序。 它从它的getEncoding
方法报告“Cp1252”:
/* java.net. */ Socket Sock = ...; InputStreamReader is = new InputStreamReader(Sock.getInputStream()); System.out.println("Character encoding = " + is.getEncoding()); // Prints "Character encoding = Cp1252"
这与系统报告的代码页不一定匹配。 例如:
C:\> CHCP 有效代码页:850
应用程序可以接收字节0x81,在代码页850中代表字符ü
。 程序使用代码页1252来解释那个字节,它没有在那个值上定义任何字符,所以我得到了一个问号。
我能够通过在启动应用程序的batch file中添加另一个命令行选项来为使用代码页850的一位客户解决此问题:
java.exe -Dfile.encoding = Cp850 ...
但是,当然,并不是所有的客户都使用代码页850。 我如何让Java使用与底层Windows系统兼容的代码页? 我的偏好是我可以放在batch file中,而不改变Java代码:
ENC = ... java.exe -Dfile.encoding =%ENC%...
cmd.exe
使用的默认编码是Cp850
(或任何“原始设备制造商”CP是本机的操作系统); 系统编码是Cp1252
(或任何“ANSI”CP是OS本地的)。 血淋淋的细节在这里 。 发现控制台编码的一种方法是通过本机代码 (请参阅GetConsoleOutputCP获取当前控制台编码;请参阅GetACP默认“ANSI”编码等 )。
通过-D
开关改变编码会影响你所有的默认编码机制,包括重定向stdout / stdin / stderr。 这不是一个理想的解决方案。
我想出了这个WSH脚本,可以将控制台设置为系统ANSI代码页,但还没有想出如何以编程方式切换到TrueType字体。
'file: setacp.vbs 'usage: cscript /Nologo setacp.vbs Set objShell = CreateObject("WScript.Shell") 'replace ACP (ANSI) with OEMCP for default console CP cp = objShell.RegRead("HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001" &_ "\Control\Nls\CodePage\ACP") WScript.Echo "Switching console code page to " & cp objShell.Exec "chcp.com " & cp
(这是我的第一个WSH脚本,所以可能有缺陷 – 我不熟悉注册表读取权限。)
使用TrueType字体是在cmd.exe
使用ANSI / Unicode的另一个要求。 在时间允许的情况下,我将会看一个更好的字体的编程开关。
关于代码snippit,正确的答案是使用适当的InputStreamReader的构造函数进行正确的代码转换。 这样,系统默认的编码是无关紧要的,你知道你正在得到一个正确的编码,对应于你在套接字上获得的编码。
那么你可以在写出文件的时候指定编码,如果需要的话,而不是依靠系统编码,当然当他们在系统上打开文件时可能会有问题,但是现代的windows系统支持UTF-8,所以你如果需要(可以在Java内部将所有字符串表示为16位unicode),可以用UTF-8写出文件。
我认为这是一般的“正确的”解决方案,可以与最大范围的底层系统兼容。
Windows有两个活动的代码页增加了复杂性。 在你的例子中,1252和850都是正确的,但是它们依赖于程序运行的方式。 对于GUI应用程序,Windows将使用ANSI代码页,西欧语言的代码页通常为1252.但是,命令行将报告相同语言环境的850代码页。
如果从chcp命令返回的代码页值将返回所需的值,则可以使用以下命令获取代码页
C:\>for /F "Tokens=4" %I in ('chcp') Do Set CodePage=%I
这将变量CodePage设置为从chcp返回的代码页值
C:\>echo %CodePage% 437
你可以在你的bat文件中用Cp前缀来使用这个值
C:\>echo Cp%CodePage% Cp437
如果你把这个放到bat文件中,第一个命令中的%I值将需要用%% I替换