Netbeans java项目属性中的汉字运行参数

sen*_*erj 5 java netbeans arguments

我正在编写一个 Netbeans java 程序来处理参数中的中文字符。我能够在编码中使用 unicode 代码和汉字,并且它们可以正确编译并显示在控制台上。但是,当我通过项目属性运行参数传递汉字时,它们都变成了??????。我已经将项目编码设置为UTF-8VM 选项-Dfile.encoding=UTF-8。这是我的编码,请帮忙。

\n
public static void main(String[] args) {\n    String test = "\\u5973\\u58eb";\n    System.out.println(test);      //works\n    String test2 = "\xe5\xa5\xb3\xe5\xa3\xab2";\n    System.out.println(test2);     //works\n    System.out.println(args[0]);   //copy&paste test2 to argument, not works, showing ??\n}\n
Run Code Online (Sandbox Code Playgroud)\n

注意:我使用 jdk 1.8.0_202、Ant v1.10.4、Windows 10、Netbeans 10,用于 Netbeans 输出和 termianl 的字体是等宽14,项目是使用 Netbeans“java 应用程序”创建的。在 Netbeans 中或 Windows 命令提示符 chcp 65001 上运行时会出现问题-Dfile.encoding=UTF-8.

\n

注意:根据 skomisa 的建议,我进一步测试了 Windows“使用 unicode utf8 进行全球语言支持”检查。我也不再使用 Netbeans,而是使用该 jar 通过 chcp 65001 在 Windows cmd 上运行。

\n
D:\\.......>java -cp dist/myjar.jar -Dfile.encoding=UTF8 java.mypackage.TestUTF8 \xe5\xa5\xb3\xe5\xa3\xab\n\xe5\xa5\xb3\xe5\xa3\xab\n\xe5\xa5\xb3\xe5\xa3\xab2\n\xc3\xa5\xc2\xa5\xc2\xb3\xc3\xa5\xc2\xa3\xc2\xab\n\nD:\\.......>java -cp dist/myjar.jar java.mypackage.TestUTF8 \xe5\xa5\xb3\xe5\xa3\xab\n??\n??2\n\xe5\xa5\xb3\xe5\xa3\xab\n
Run Code Online (Sandbox Code Playgroud)\n

因此,对于-Dfile.encoding=UTF8(第一次运行),编码中的常量字符串有效,而参数则无效。没有-Dfile.encoding(第二次运行),代码内常量将无法工作,而参数可以工作。但我两者都需要。我的程序和程序参数中有中文常量字符串。有人可以告诉我可以做什么吗?

\n

sko*_*isa 1

基于对 SO 上类似问题的回答,似乎将 Unicode 参数传递给 Java 应用程序从未正常工作。没有简单的解决方案,但您可以使用JNA (Java Native Access) 解决此问题。

\n

JNA 允许您从 Java 调用 Windows API 方法,而无需使用native代码。因此,在 Java 应用程序中,您可以直接调用 Win API 方法,例如GetCommandLineW()CommandLineToArgvW(),以访问有关用于调用程序的命令行的详细信息,包括传递的任何参数。这两种方法都支持 Unicode。

\n

执行此操作的代码并不简单,但也不是过于复杂。下面的方法基于 Sergey Karpushin在Passing command line unicode argument to Java code 的回答中的代码

\n

为了编译代码,您将需要几个 jar:jna.jarjna-platform.jar。您可以从JNA 5.10.0 下载的dist目录或从 Maven获取这些内容。

\n

此方法既可以在 NetBeans 中使用,也可以在 Windows 10 的命令行中使用,但存在一些显着的差异:

\n
    \n
  • 您必须从命令行调用chcp 65001,并在java.exe调用中指定-Dfile.encoding=UTF-8
  • \n
  • 提取返回的参数时,CommandLineToArgvW()您可能会发现 NetBeans 中返回的参数与命令行中返回的参数之间存在差异。但这并不是真正的问题,因为您感兴趣的唯一参数是末尾的参数,这些参数位于包含 jar 文件名的参数之后。
  • \n
\n

这是代码:

\n
package chinesearg;\n\nimport com.sun.jna.Native;\nimport com.sun.jna.Pointer;\nimport com.sun.jna.WString;\nimport com.sun.jna.ptr.IntByReference;\nimport com.sun.jna.win32.StdCallLibrary;\nimport java.util.ArrayList;\nimport java.util.List;\n\n// Proof of concept application which uses JNA to correctly process command\n// line arguments containing Chinese characters using JNA. \n//\n// Credit to Sergey Karpushin for the approach used in this this code.\n// See this SO answer: /sf/answers/2934643631/\npublic class ChineseArg {\n\n    private final Kernel32 kernel32 = Native.load("kernel32", Kernel32.class);\n    private final Shell32 shell32 = Native.load("shell32", Shell32.class);\n\n    public static void main(String[] args) {\n\n        String test = "\\u5973\\u58eb";\n        System.out.println(test);      //works\n        String test2 = "\xe5\xa5\xb3\xe5\xa3\xab2";\n        System.out.println(test2);     //works\n        System.out.println("args.length=" + args.length);\n        for (int i=0; i< args.length; i++) {\n            System.out.println("args[" + i + "] = "+args[i]);\n        }\n        String[] params = new ChineseArg().getCommandLineArguments();\n        if (params == null) {\n            System.out.println("getCommandLineArguments() returned null.");\n        } else {\n            int count = params.length;\n            System.out.println("Number of params=" + count);\n            for (int i = 0; i < count; i++) {\n                System.out.println("params[" + i + "]=" + params[i]);\n            }\n        }\n    }\n\n    private String[] getCommandLineArguments() {\n\n        System.out.println("Active code page is " + Kernel32.INSTANCE.GetConsoleCP());\n        String[] ret = getFullCommandLine();\n        List<String> argsOnly = null;\n\n        for (int i = 0; i < ret.length; i++) {\n            if (argsOnly != null) {\n                argsOnly.add(ret[i]);\n            } else if (ret[i].toLowerCase().endsWith(".jar")) {\n                argsOnly = new ArrayList<>();\n            }\n        }\n        if (argsOnly != null) {\n            ret = argsOnly.toArray(new String[0]);\n        }\n        return ret;\n    }\n\n    private String[] getFullCommandLine() {\n\n        IntByReference argc = new IntByReference();\n        Pointer argv_ptr = shell32.CommandLineToArgvW(kernel32.GetCommandLineW(), argc);\n        String[] argv = argv_ptr.getWideStringArray(0, argc.getValue());\n        kernel32.LocalFree(argv_ptr);\n        return argv;\n    }\n}\n\ninterface Kernel32 extends StdCallLibrary {\n    static Kernel32 INSTANCE = Native.load("kernel32", Kernel32.class, com.sun.jna.win32.W32APIOptions.DEFAULT_OPTIONS);\n    WString GetCommandLineW();\n    int GetConsoleCP();\n    Pointer LocalFree(Pointer pointer);\n}\n\ninterface Shell32 extends StdCallLibrary {\n    Pointer CommandLineToArgvW(WString command_line, IntByReference argc);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

这是从命令提示符运行时的示例输出,显示第一个参数 ("\xe5\xa5\xb3\xe5\xa3\xab2") 被正确捕获:

\n
C:\\Users\\johndoe>chcp 65001\nActive code page: 65001\n\nC:\\Users\\johndoe>java -Dfile.encoding=UTF-8 -jar "D:\\NB126\\ChineseArg\\dist\\ChineseArg.jar" "\xe5\xa5\xb3\xe5\xa3\xab2"  "\\u5973\\u58eb"\n\xe5\xa5\xb3\xe5\xa3\xab\n\xe5\xa5\xb3\xe5\xa3\xab2\nargs.length=2\nargs[0] = ??2\nargs[1] = \\u5973\\u58eb\nActive code page is 65001\nNumber of params=2\nparams[0]=\xe5\xa5\xb3\xe5\xa3\xab2\nparams[1]=\\u5973\\u58eb\n\nC:\\Users\\johndoe>\n
Run Code Online (Sandbox Code Playgroud)\n

笔记:

\n
    \n
  • 此代码解决了 Windows 环境中的限制。我不知道如果这段代码在 macOS 或 Linux 上运行会发生什么。
  • \n
  • 尽管这违背了您的问题的精神,但还有一种替代方法:将参数作为转义的 Unicode 传递给应用程序。使用 Apache 的StringEscapeUtils.unescapeJava()转义数据非常简单。如果可行的话就根本不需要 JNA。
  • \n
\n