2009-12-09 7 views
6

Je souhaite lancer un navigateur et charger une page Web à l'aide de l'exécutable Runtime de Java. L'appel exact ressemble à ceci:Java Runtime Exec sous Windows échoue avec Unicode dans les arguments

String[] explorer = {"C:\\Program Files\\Internet Explorer\\IEXPLORE.EXE", 
    "-noframemerging", 
    "C:\\ ... path containing unicode chars ... \\Main.html"}; 
Runtime.getRuntime().exec(explorer); 

Dans mon cas, le chemin contient "\u65E5\u672C\u8A9E", les caractères & # x65e5; & # x672c; & # x8a9e ;.

Apparemment, il est un bug java: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4947220

Ma question est: est-il une solution viable qui peut être fait uniquement à l'aide de Java? Il semble qu'il est possible d'écrire une bibliothèque JNI pour cela, mais j'aimerais éviter cela si possible. J'ai essayé le codage URI du chemin en tant qu'ascii et en écrivant les commandes dans un fichier séquentiel, sans succès.

Répondre

0

Ce sont les deux solutions que je considérais, chacun d'entre eux sont des solutions de contournement plus ou moins:

  1. Création d'un fichier html redirect temp qui redirige le navigateur vers la page appropriée. Notez que IE attend unicode non codé pour les fichiers locaux, alors que les autres navigateurs acceptent uniquement les chemins de fichier encodés en uri.

  2. Utilisez le nom de fichier court pour le fichier Windows. Il ne contiendra pas de caractères Unicode.

-1

Je pense que vous pouvez utiliser Apache Commons Exec bibliothèque ou ProcessBuilder pour donner un essai;)

+0

ProcessBuilder semble avoir le même problème avec unicode dans sa chaîne d'argument de commande. Je ne peux malheureusement pas apporter une bibliothèque extérieure pour mon cas particulier. – Bear

+0

Que diriez-vous d'initialiser vos arguments aux variables en utilisant la méthode getPath() et les utiliser dans ProcessBuilder sans toucher à des trucs non-unicode dans le code source? – israkir

+0

Apache Commons Exec utilise l'API Runtime.exec() en interne, vous aurez toujours le même problème qu'avant. – Renan

2

Au mentionné Java bug page, vous trouverez une solution de contournement qui est présenté au travail en utilisant ProcessBuilder et enveloppant les paramètres des variables d'environnement. Voici le code source de Parag Thakur:

String[] cmd = new String[]{"yourcmd.exe", "Japanese CLI argument: \ufeff\u30cb\u30e5\u30fc\u30b9"};   
Map<String, String> newEnv = new HashMap<String, String>(); 
newEnv.putAll(System.getenv()); 
String[] i18n = new String[cmd.length + 2]; 
i18n[0] = "cmd"; 
i18n[1] = "/C"; 
i18n[2] = cmd[0]; 
for (int counter = 1; counter < cmd.length; counter++) 
{ 
    String envName = "JENV_" + counter; 
    i18n[counter + 2] = "%" + envName + "%"; 
    newEnv.put(envName, cmd[counter]); 
} 
cmd = i18n; 

ProcessBuilder pb = new ProcessBuilder(cmd); 
Map<String, String> env = pb.environment(); 
env.putAll(newEnv); 
final Process p = pb.start(); 
0

Nous avons utilisé un JNI pour démarrer des processus de Java depuis des années. Ni Runtime.exec ni ProcessBuilder ne fonctionneront, et il semble peu probable qu'ils règlent cela, étant donné que cela fait déjà longtemps. Toutefois, vous devriez pouvoir contourner le problème en utilisant le flux d'entrée, une socket ou des variables d'environnement pour transmettre les paramètres. Si vous n'avez pas de contrôle direct sur l'exécutable, vous devrez créer un wrapper.

0

Vous pouvez utiliser JNA. Avec la version 3.3.0 ou appelez plus tard CreateProcess:

WinBase.PROCESS_INFORMATION.ByReference processInfo = 
    new WinBase.PROCESS_INFORMATION.ByReference(); 
WinBase.STARTUPINFO startupInfo = new WinBase.STARTUPINFO(); 

String command = "C:\\Program Files\\Internet Explorer\\IEXPLORE.EXE " + 
    "-noframemerging \"C:\\\u65E5\u672C\u8A9E\\Main.html\""; 

if (!Kernel32.INSTANCE.CreateProcess(
    null,   // Application name, not needed if supplied in command line 
    command,  // Command line 
    null,   // Process security attributes 
    null,   // Thread security attributes 
    true,   // Inherit handles 
    0,    // Creation flags 
    null,   // Environment 
    null,   // Directory 
    startupInfo, 
    processInfo)) 
{ 
    throw new IllegalStateException("Error creating process. Last error: " + 
     Kernel32.INSTANCE.GetLastError()); 
} 

// The CreateProcess documentation indicates that it is very important to 
// close the returned handles 
Kernel32.INSTANCE.CloseHandle(processInfo.hThread); 
Kernel32.INSTANCE.CloseHandle(processInfo.hProcess); 

long pid = processInfo.dwProcessId.longValue(); 

Réorientation sortie du processus enfant est un peu plus difficile mais pas impossible.

0

Créez un fichier .bat/.sh. Écrivez vos commandes dans ce fichier et exécutez-le. Assurez-vous que vous avez changé la page de code en unicode dans le cas de Windows (chcp 65001). Par exemple, pour exécuter la commande ci-dessous dans les fenêtres:

String[] command ={"C:\\aconex\\学校\\mysql\\bin\\mysql", "-esource", "大村箕島a\\data.sql"}; 

Créer un fichier temporaire appelé temp.bat et exécuter avec le Runtime.getRuntime() exec Temp..bat

chcp 65001 
C:\aconex\学校\mysql\bin\mysql -esource 大村箕島a\data.sql