我必须将日语命令行参数传递给Java main方法。如果我在命令行窗口中键入Unicode字符,则会显示“?????”哪个没问题,但传递给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特定的脚本语言)。
这是因为默认情况下,他们使用特定于语言环境的代码页读取输入和输出,这不是UTF,与使用UTF-8的其他所有现代操作系统不同。
您可以使用。将终端的代码页更改为其他内容 chcp
命令,支持UTF-8编码 chcp 65001
以某种方式打破了可能导致应用程序致命的应用程序。
如果您只需要日语,则可以通过将区域设置(“区域设置”中的“非Unicode应用程序的语言”)设置为日本来切换到代码页932(类似于Shift-JIS)。但是,对于不在该代码页中的字符,这仍然会失败。
如果需要在Windows上通过命令行可靠地获取非ASCII字符,则需要调用Win32 API函数 GetCommandLineW
直接避免编码到系统代码页面层。可能你想用JNA做到这一点。
遗憾的是,标准Java启动程序在Windows上处理Unicode命令行参数时存在已知且长期存在的错误。也许在其他一些平台上。对于Java 7更新1,它仍然存在。
如果你擅长用C / C ++编程,你可以尝试编写自己的启动器。一些专门的发射器可能不是什么大问题...只需看看最初的例子 JNI调用API 页。
另一种可能性是使用Java包装器和临时文件的组合将Unicode参数传递给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