2011-10-05 11 views
11

Muszę przekazać argument wiersza polecenia, który jest metodą główną od japońskiego do Javy. Jeśli wpiszę znaki Unicode w oknie wiersza polecenia, wyświetli się "?????" co jest w porządku, ale wartość przekazana do programu java jest również "?????". Jak uzyskać poprawną wartość argumentu przekazanego przez okno poleceń? Poniżej znajduje się przykładowy program, który zapisuje do pliku wartość podaną przez argument wiersza poleceń.Przekazywanie argumentu unicode z wiersza komend do kodu 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

Czy to zmienić, kiedy zmienić zestaw znaków w oknie konsoli? Który system operacyjny? – Andreas

+1

Zmiana zestawu znaków w oknie konsoli nie pomaga. Używam systemu Windows 2000 –

Odpowiedz

0

Problem jest spowodowany ustawieniami regionalnymi systemu. Zmień ustawienia regionalne na japoński i będzie działać.

Oto jak to zrobić http://www.java.com/en/download/help/locale.xml

+0

nie powinniśmy być w stanie przekazać żadnej wartości Unicode, czy japoński lub koreański bez zmiany ustawień regionalnych? W tej chwili nie ma zasobów, aby to zrobić, da mu szansę. –

+0

To jest tylko obejście dla jednego języka. Co zrobić, jeśli dana osoba ma na swoim komputerze więcej niż jeden język inny niż angielski? Jeśli inne aplikacje (np. Notatnik) mogą obsługiwać litery inne niż angielskie, aplikacja java musi również być w stanie to zrobić bez zmiany ustawień regionalnych. Zobacz odpowiedź poniżej http://stackoverflow.com/a/41923480/285060, która nie będzie wymagać zmiany ustawień regionalnych systemu operacyjnego –

-2

Java działa wewnętrznie Unicode, więc podczas kompilacji kodu źródłowego, które używane chińskich kodowania takich jak Big5 lub GB2312, trzeba określić kodowanie do kompilatora, aby prawidłowo przekonwertuj go do Unicode.

javac -encoding big5 sourcefile.java 

lub

javac -encoding gb2312 sourcefile.java 

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

+0

Jest to całkowicie nieistotne dla pytania. Pytanie dotyczy wywoływania aplikacji z symbolami unicode w args. NIE chodzi o kompilowanie kodu źródłowego zawierającego symbole Unicode. –

10

Niestety nie można wiarygodnie używać znaków spoza ASCII z aplikacji wiersza polecenia, które korzystają stdlib okien C Runtime, podobnie jak Java (i dość dużo wszystkie języki skryptowe specyficzne dla systemu Windows).

Dzieje się tak dlatego, że domyślnie odczytują dane wejściowe i wyjściowe za pomocą strony kodowej specyficznej dla ustawień regionalnych, która nigdy nie jest formatem UTF, w przeciwieństwie do każdego innego nowoczesnego systemu operacyjnego korzystającego z formatu UTF-8.

Mimo że możesz zmienić stronę kodową terminala na inną, używając komendy chcp, obsługa kodowania UTF-8 pod chcp 65001 jest zepsuta na kilka sposobów, które mogą spowodować fatalne wyzwolenie aplikacji.

Jeśli potrzebujesz tylko języka japońskiego, możesz przejść do strony kodowej 932 (podobnie jak Shift-JIS), ustawiając ustawienia narodowe ("język dla aplikacji nieobsługujących kodów Unicode" w ustawieniach regionalnych) w Japonii. To nadal będzie nie działać dla znaków, które nie są na tej stronie kodowej.

Jeśli potrzebujesz niezawodnie uzyskać znaki spoza ASCII w wierszu poleceń w systemie Windows, musisz wywołać funkcję Win32 API GetCommandLineW bezpośrednio, aby uniknąć warstwy kodującej kodowanie do kodu systemowego. Prawdopodobnie chcesz to zrobić za pomocą JNA.

5

Niestety standardowy program uruchamiający Java ma znany i długotrwały błąd w obsłudze argumentów wiersza poleceń Unicode w systemie Windows. Może na innych platformach. Dla aktualizacji Java 7 1 nadal była na miejscu.

Jeśli czujesz się dobrze w programowaniu w języku C/C++, możesz spróbować napisać własny program uruchamiający. Niektóre wyspecjalizowane programy uruchamiające mogą nie być wielkim problemem ... Zobacz pierwszy przykład na stronie JNI Invocation API.

Inną możliwością jest użycie kombinacji opakowania Java i pliku tymczasowego do przekazywania parametrów Unicode do aplikacji Java. Zobacz mój blog Java, Xalan, Unicode command line arguments..., aby uzyskać więcej komentarzy i kod opakowania.

0

Można użyć JNA, aby ta, oto kopiuj-wklej z mojego kodu:

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

Oprócz znanego log4j kod ten zależy również od

<dependency> 
    <groupId>net.java.dev.jna</groupId> 
    <artifactId>jna</artifactId> 
    <version>4.3.0</version> 
</dependency> 
Powiązane problemy