Forma multiplataforma para abrir un archivo usando Java 1.5
linux file-association (8)
Puede usar la forma predeterminada del sistema operativo para abrirlo por usted.
- Windows: "cmd / c fileName
- Linux w / gnome " nombre de archivo gnome-abierto"
- Linux w / Kde?
- OSx " nombre de archivo abierto"
Estoy usando Java 1.5 y me gustaría iniciar la aplicación asociada para abrir el archivo. Sé que Java 1.6 introdujo la API de escritorio , pero necesito una solución para Java 1.5 .
Hasta ahora encontré la manera de hacerlo en Windows:
Runtime.getRuntime().exec(new String[]{ "rundll32",
"url.dll,FileProtocolHandler", fileName });
¿Hay una forma de plataforma cruzada para hacerlo? ¿O al menos una solución similar para Linux ?
Solo como una adición: en lugar de gnome-open
, usa xdg-open
. Es parte de XdgUtils , que a su vez son parte del paquete de soporte de LSB Desktop (comenzando con 3.2).
Puede (debería) seguir utilizando gnome-open
como alternativa, pero xdg-open
también funcionará en escritorios que no sean de GNOME.
JDIC es una biblioteca que proporciona funcionalidad similar a Desktop en Java 1.5.
SWT le brinda la posibilidad de solicitar que el programa estándar abra un archivo a través de:
final Program p = Program.findProgram(fileExtension);
p.execute(file.getAbsolutePath());
Estrictamente, esto no es multiplataforma ya que SWT depende de la plataforma, pero para cada plataforma puede usar un jarrón SWT diferente.
public static boolean isWindows() {
String os = System.getProperty("os.name").toLowerCase();
return os.indexOf("windows") != -1 || os.indexOf("nt") != -1;
}
public static boolean isMac() {
String os = System.getProperty("os.name").toLowerCase();
return os.indexOf("mac") != -1;
}
public static boolean isLinux() {
String os = System.getProperty("os.name").toLowerCase();
return os.indexOf("linux") != -1;
}
public static boolean isWindows9X() {
String os = System.getProperty("os.name").toLowerCase();
return os.equals("windows 95") || os.equals("windows 98");
}
y
if (isLinux())
{
cmds.add(String.format("gnome-open %s", fileName));
String subCmd = (exec) ? "exec" : "openURL";
cmds.add(String.format("kfmclient "+subCmd+" %s", fileName));
}
else if (isMac())
{
cmds.add(String.format("open %s", fileName));
}
else if (isWindows() && isWindows9X())
{
cmds.add(String.format("command.com /C start %s", fileName));
}
else if (isWindows())
{
cmds.add(String.format("cmd /c start %s", fileName));
}
Otra respuesta (por boutta) sugiere usar SWT. No recomendaría hacer referencia a la biblioteca solo para este propósito, pero si ya la está utilizando, simplemente ejecute:
Program.launch("http://google.com/");
Tenga en cuenta que este método solo funcionará (y devolverá true
) si un objeto Display
ya se ha creado (por ejemplo, al crear un Shell
). También tenga en cuenta que debe ejecutarse en el hilo principal; p.ej:
Display.syncExec(new Runnable() {
public void run() {
Program.launch("http://google.com/");
}
});
En el ejemplo anterior, he lanzado una URL, pero el inicio de archivos funciona de la misma manera.
+1 por esta respuesta
Además sugeriría la siguiente implementación usando polimorfismo:
De esta manera, puede agregar una nueva plataforma más fácilmente al reducir el acoplamiento entre las clases.
El código del cliente:
Desktop desktop = Desktop.getDesktop();
desktop.open( aFile );
desktop.imaginaryAction( aFile );
La impl de escritorio:
package your.pack.name;
import java.io.File;
public class Desktop{
// hide the constructor.
Desktop(){}
// Created the appropriate instance
public static Desktop getDesktop(){
String os = System.getProperty("os.name").toLowerCase();
Desktop desktop = new Desktop();
// This uf/elseif/else code is used only once: here
if ( os.indexOf("windows") != -1 || os.indexOf("nt") != -1){
desktop = new WindowsDesktop();
} else if ( os.equals("windows 95") || os.equals("windows 98") ){
desktop = new Windows9xDesktop();
} else if ( os.indexOf("mac") != -1 ) {
desktop = new OSXDesktop();
} else if ( os.indexOf("linux") != -1 && isGnome() ) {
desktop = new GnomeDesktop();
} else if ( os.indexOf("linux") != -1 && isKde() ) {
desktop = new KdeDesktop();
} else {
throw new UnsupportedOperationException(String.format("The platform %s is not supported ",os) );
}
return desktop;
}
// default implementation :(
public void open( File file ){
throw new UnsupportedOperationException();
}
// default implementation :(
public void imaginaryAction( File file ){
throw new UnsupportedOperationException();
}
}
// One subclass per platform below:
// Each one knows how to handle its own platform
class GnomeDesktop extends Desktop{
public void open( File file ){
// Runtime.getRuntime().exec: execute gnome-open <file>
}
public void imaginaryAction( File file ){
// Runtime.getRuntime().exec:gnome-something-else <file>
}
}
class KdeDesktop extends Desktop{
public void open( File file ){
// Runtime.getRuntime().exec: kfmclient exec <file>
}
public void imaginaryAction( File file ){
// Runtime.getRuntime().exec: kfm-imaginary.sh <file>
}
}
class OSXDesktop extends Desktop{
public void open( File file ){
// Runtime.getRuntime().exec: open <file>
}
public void imaginaryAction( File file ){
// Runtime.getRuntime().exec: wow!! <file>
}
}
class WindowsDesktop extends Desktop{
public void open( File file ){
// Runtime.getRuntime().exec: cmd /c start <file>
}
public void imaginaryAction( File file ){
// Runtime.getRuntime().exec: ipconfig /relese /c/d/e
}
}
class Windows9xDesktop extends Desktop{
public void open( File file ){
//Runtime.getRuntime().exec: command.com /C start <file>
}
public void imaginaryAction( File file){
//Runtime.getRuntime().exec: command.com /C otherCommandHere <file>
}
}
Esto es solo un ejemplo, en la vida real no vale la pena crear una nueva clase solo para parametrizar un valor (la cadena de comandos% s). Pero imaginemos que cada método realiza otros pasos de una manera específica para la plataforma.
Al hacer este tipo de acercamiento, se pueden eliminar los constructos innecesarios if / elseif / else que con el tiempo pueden introducir errores (si hay 6 de ellos en el código y se necesita un cambio, puede olvidarse de actualizar uno de ellos, o mediante copia / pegando puede olvidarse de cambiar el comando para ejecutar)
Nosotros ponemos el comando afuera en alguna parte en el archivo de configuración.
Su "JAR y código fuente" será "multiplataforma", pero su implementación no.
También puedes hacer algo como esta respuesta . Puede poner el nombre de clase de la clase de fábrica de la implementación "Deskop" en el archivo de instalación. (puede ser guía o primavera, si lo desea)