最近开发java控制台项目,由于用了第三方库,必须使用utf8字符。当然在开发环境eclipse下,显示是正常的:
但是windows的控制台,却是输出乱码。
虽然不改,程序逻辑是正确,作为偏执狂还是翻阅了各种资料:
网上各种文章,不是用chcp改变控制台编码,就是建议修改程序编码为GBK。
参考了stackoverflow的一篇文章,找到一种使用Windows内核API的方案
核心是封装一个Console类 package demo;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.win32.StdCallLibrary;
/**
* For unicode output on windows platform
*
* @author Sandy_Yin
*
*/
public class Console {
private static Kernel32 INSTANCE = null;
public interface Kernel32 extends StdCallLibrary {
public Pointer GetStdHandle(int nStdHandle);
public boolean WriteConsoleW(Pointer hConsoleOutput, char[] lpBuffer,
int nNumberOfCharsToWrite,
IntByReference lpNumberOfCharsWritten, Pointer lpReserved);
}
static {
String os = System.getProperty("os.name").toLowerCase();
if (os.startsWith("win")) {
INSTANCE = (Kernel32) Native
.loadLibrary("kernel32", Kernel32.class);
}
}
public static void print(String message) {
if (!prePrint(message))
System.out.print(message);
}
protected static boolean prePrint(String message) {
boolean successful = false;
if (INSTANCE != null) {
Pointer handle = INSTANCE.GetStdHandle(-11);
char[] buffer = message.toCharArray();
IntByReference lpNumberOfCharsWritten = new IntByReference();
successful = INSTANCE.WriteConsoleW(handle, buffer, buffer.length,
lpNumberOfCharsWritten, null);
}
return successful;
}
public static void println(String message) {
// from
// http://stackoverflow.com/questions/54952/java-utf-8-and-windows-console
if (prePrint(message)) {
System.out.println();
} else {
System.out.println(message);
}
}
}
对输出进行测试,使用命令:java -jar sample.jar,发现输出还是一样。
添加命令行参数,使用java -Dfile.encoding=utf8 -jar sample.jar,就达到效果了。
PS:此方法还存在一些缺陷,但并不是Console类造成的。上图中“测试”前有一个空白的地方,这是应为使用utf8方式读入非UTF8文件产生的。在文件开始会出现空格。
代码下载/Files/anic/utf8sample_source.zip
/Files/anic/utf8sample_runtime.zip