2011-10-05 15 views
11

Tengo que pasar el argumento de la línea de comando que es el método principal de Java a Java. Si escribo caracteres Unicode en la ventana de línea de comandos, aparece '?????' lo cual está bien, pero el valor pasado al programa java también es '?????'. ¿Cómo obtengo el valor correcto del argumento pasado por la ventana de comandos? A continuación se muestra un programa de ejemplo que escribe en un archivo el valor proporcionado por el argumento de línea de comando.Pasando la línea de comando argumento unicode al código 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(); 
     } 
    } 
+1

¿Cambia cuando cambiar el juego de caracteres de la ventana de la consola? ¿Qué sistema operativo? – Andreas

+1

Cambiar el juego de caracteres de la ventana de la consola no ayuda. Estoy usando Windows 2000 –

Respuesta

0

El problema se debe a la configuración regional del sistema. Cambie su configuración regional a japonés y funcionaría.

Aquí es cómo hacer esto http://www.java.com/en/download/help/locale.xml

+0

¿no deberíamos poder pasar cualquier valor Unicode, ya sea japonés o coreano, sin cambiar la configuración regional del sistema? En este momento no tiene recursos para hacerlo, le dará una oportunidad. –

+0

Esto es solo una solución para un idioma. ¿Qué pasa si la persona tiene más de 1 idioma no inglés en su computadora? Si otras aplicaciones (como el bloc de notas) pueden manejar letras que no sean inglesas, la aplicación java también debe poder hacerlo sin cambiar la configuración regional del sistema. Consulte la respuesta a continuación http://stackoverflow.com/a/41923480/285060 que no requerirá cambiar la configuración regional del sistema operativo –

-2

Java trabaja internamente con Unicode, por lo que al compilar los archivos de código fuente que utilizan una codificación china como Big5 o GB2312, es necesario especificar la codificación para el compilador con el fin de adecuadamente convertirlo a Unicode.

javac -encoding big5 sourcefile.java 

o

javac -encoding gb2312 sourcefile.java 

Referencia: http://www.chinesecomputing.com/programming/java.html

+0

Esto es completamente irrelevante para la pregunta. La pregunta se trata de invocar la aplicación con símbolos Unicode en args. NO se trata de compilar el código fuente que tiene símbolos Unicode. –

10

Lamentablemente no se puede utilizar de forma fiable caracteres no ASCII con aplicaciones de línea de comandos que utilizan stdlib del tiempo de ejecución de Windows C, como Java (y más o menos todos los lenguajes de scripting no específicos de Windows realmente).

Esto se debe a que leen sus entradas y salidas utilizando una página de códigos específicos del lugar por defecto, que nunca es un UTF, a diferencia de cualquier otro sistema operativo moderno que utiliza UTF-8.

Si bien puede cambiar la página de códigos de un terminal por otra cosa utilizando el comando chcp, la compatibilidad con la codificación UTF-8 bajo chcp 65001 se interrumpe de varias maneras que probablemente provoquen un error fatal en las aplicaciones.

Si solo necesita japonés puede cambiar a la página de códigos 932 (similar a Shift-JIS) estableciendo su configuración regional ('idioma para aplicaciones que no son Unicode' en la configuración Regional) en Japón. Sin embargo, esto aún fallará para los personajes que no están en esa página de códigos.

Si necesita obtener caracteres no ASCII a través de la línea de comandos de manera confiable en Windows, debe llamar directamente a la función Win32 API GetCommandLineW para evitar la capa encode-to-system-code-page. Probablemente quieras hacer eso usando JNA.

5

Desafortunadamente, el iniciador de Java estándar tiene un error conocido y de larga vida en el manejo de argumentos de línea de comandos Unicode en Windows. Quizás en algunas otras plataformas también. Para Java 7 actualización 1 todavía estaba en su lugar.

Si se siente bien programando en C/C++, puede intentar escribir su propio iniciador. Algunos lanzadores especializados podrían no ser tan importantes ... Solo vea el ejemplo inicial en la página JNI Invocation API.

Otra posibilidad es utilizar una combinación de un contenedor Java y un archivo temporal para pasar parámetros Unicode a una aplicación Java. Vea mi blog Java, Xalan, Unicode command line arguments... para más comentarios y el código del contenedor.

0

Puede utilizar JNA para conseguir eso, aquí es copiar y pegar de mi código:

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); 
} 

Además de log4j conocido este código también depende de

<dependency> 
    <groupId>net.java.dev.jna</groupId> 
    <artifactId>jna</artifactId> 
    <version>4.3.0</version> 
</dependency> 
Cuestiones relacionadas