将命令行unicodeparameter passing给Java代码
我必须通过日本的命令行参数到Java主要方法。 如果我在命令行窗口中inputUnicode字符,它会显示'?????' 这是可以的,但是传递给java程序的值也是'?????'。 如何获得命令窗口传递的参数的正确值? 下面是一个示例程序,它将通过命令行参数提供的值写入文件。
public static void main(String[] args) { String input = args[0]; try { String filePath = "C:/Temp/abc.txt"; File file = new File(filePath); OutputStream out = new FileOutputStream(file); byte buf[] = new byte[1024]; int len; InputStream is = new ByteArrayInputStream(input.getBytes()); while ((len = is.read(buf)) > 0) { out.write(buf, 0, len); } out.close(); is.close(); } catch (Exception e) { e.printStackTrace(); } }
不幸的是,你不能可靠地使用非ASCII字符的命令行应用程序使用Windows C运行时的stdlib,如Java(几乎所有非Windows特定的脚本语言)。
这是因为他们默认使用特定于语言环境的代码页来读取input和输出,这与使用UTF-8的所有其他现代操作系统不同。
虽然您可以使用chcp
命令将terminal的代码页更改为其他内容,但对chcp 65001
下的UTF-8编码的支持有几种方式可能会导致应用程序chcp 65001
故障。
如果您只需要日语,则可以通过在日本设置区域设置(区域设置中的“非Unicode应用程序的语言”),切换到代码页932(类似于Shift-JIS)。 对于不在该代码页中的字符,这仍然会失败。
如果您需要在Windows上可靠地通过命令行获取非ASCII字符,则需要直接调用Win32 API函数GetCommandLineW
以避免编码到系统代码页面层。 可能你会想用JNA来做到这一点。
不幸的是,标准的Java启动程序在处理Windows上的Unicode命令行参数时有一个已知和长期存在的bug。 也许在其他一些平台上。 对于Java 7更新1,它仍然存在。
如果您对C / C ++编程感觉良好,您可以尝试编写自己的启动器。 一些专门的启动器可能没有什么大不了的…只要看看JNI调用API页面的最初例子。
另一种可能性是使用Java包装器和临时文件的组合将Unicodeparameter passing给Java应用程序。 查看我的博客Java,Xalan,Unicode命令行参数…以获得更多评论和封装代码。
这个问题是因为你的系统语言环境。 更改您的语言环境为日语,它会工作。
你可以使用JNA来获取,这是从我的代码复制粘贴:
import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.apache.log4j.Logger; import com.sun.jna.Native; import com.sun.jna.Pointer; import com.sun.jna.WString; import com.sun.jna.ptr.IntByReference; import com.sun.jna.win32.StdCallLibrary; public class OsNativeWindowsImpl implements OsNative { private static Logger log = Logger.getLogger(OsNativeWindowsImpl.class); private Kernel32 kernel32; private Shell32 shell32; /** * This method will try to solve issue when java executable cannot transfer * argument in utf encoding. cyrillic languages screws up and application * receives ??????? instead of real text */ @Override public String[] getCommandLineArguments(String[] fallBackTo) { try { log.debug("In case we fail fallback would happen to: " + Arrays.toString(fallBackTo)); String[] ret = getFullCommandLine(); log.debug("According to Windows API programm was started with arguments: " + Arrays.toString(ret)); List<String> argsOnly = null; for (int i = 0; i < ret.length; i++) { if (argsOnly != null) { argsOnly.add(ret[i]); } else if (ret[i].toLowerCase().endsWith(".jar")) { argsOnly = new ArrayList<>(); } } if (argsOnly != null) { ret = argsOnly.toArray(new String[0]); } log.debug("These arguments will be used: " + Arrays.toString(ret)); return ret; } catch (Throwable t) { log.error("Failed to use JNA to get current program command line arguments", t); return fallBackTo; } } private String[] getFullCommandLine() { try { // int pid = kernel32.GetCurrentProcessId(); IntByReference argc = new IntByReference(); Pointer argv_ptr = getShell32().CommandLineToArgvW(getKernel32().GetCommandLineW(), argc); String[] argv = argv_ptr.getWideStringArray(0, argc.getValue()); getKernel32().LocalFree(argv_ptr); return argv; } catch (Throwable t) { throw new RuntimeException("Failed to get program arguments using JNA", t); } } private Kernel32 getKernel32() { if (kernel32 == null) { kernel32 = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class); } return kernel32; } private Shell32 getShell32() { if (shell32 == null) { shell32 = (Shell32) Native.loadLibrary("shell32", Shell32.class); } return shell32; } } interface Kernel32 extends StdCallLibrary { int GetCurrentProcessId(); WString GetCommandLineW(); Pointer LocalFree(Pointer pointer); } interface Shell32 extends StdCallLibrary { Pointer CommandLineToArgvW(WString command_line, IntByReference argc); }
除了众所周知的log4j这个代码也依赖于
<dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> <version>4.3.0</version> </dependency>
Java在内部使用Unicode工作,因此在编译使用中文编码(如Big5或GB2312)的源代码文件时,需要指定编码器的编码以便将其正确地转换为Unicode。
javac -encoding big5 sourcefile.java
要么
javac -encoding gb2312 sourcefile.java
参考: http : //www.chinesecomputing.com/programming/java.html