2009-06-16 6 views
7

Mientras buscaba cómo hacer esto, encontré una discusión vaga sobre diferentes opciones, como JNI vs JNA, pero no mucho en cuanto a ejemplos concretos.¿Cuál es la forma más fácil de llamar a una función de kernel de Windows desde Java?

Contexto: si Java de File.renameTo() no puede hacer su trabajo (por cualquier razón; it is a little problematic), me gustaría volver a caer a directamente a través de esta función nativa de Windows, que se define en kernel32.dll (from this answer):

BOOL WINAPI MoveFile(
    __in LPCTSTR lpExistingFileName, 
    __in LPCTSTR lpNewFileName 
); 

Entonces, usando cualquier enfoque, ¿cómo llamarías exactamente esa función desde dentro del código Java? Estoy buscando la forma más sencilla, con la cantidad mínima de código que no es Java o pasos adicionales (por ejemplo, en compilación o implementación).

Respuesta

7

Si va con JNA, considere invocar MoveFileW directamente - ahorra tener que proporcionar información de configuración para elegir entre llamadas Unicode y ANSI.

import java.io.*; 
import com.sun.jna.*; 

public class Ren { 

    static interface Kernel32 extends Library { 
    public static Kernel32 INSTANCE = (Kernel32) Native 
     .loadLibrary("Kernel32", Kernel32.class); 

    public static int FORMAT_MESSAGE_FROM_SYSTEM = 4096; 
    public static int FORMAT_MESSAGE_IGNORE_INSERTS = 512; 

    public boolean MoveFileW(WString lpExistingFileName, 
     WString lpNewFileName); 

    public int GetLastError(); 

    public int FormatMessageW(int dwFlags, 
     Pointer lpSource, int dwMessageId, 
     int dwLanguageId, char[] lpBuffer, int nSize, 
     Pointer Arguments); 
    } 

    public static String getLastError() { 
    int dwMessageId = Kernel32.INSTANCE.GetLastError(); 
    char[] lpBuffer = new char[1024]; 
    int lenW = Kernel32.INSTANCE.FormatMessageW(
     Kernel32.FORMAT_MESSAGE_FROM_SYSTEM 
      | Kernel32.FORMAT_MESSAGE_IGNORE_INSERTS, null, 
     dwMessageId, 0, lpBuffer, lpBuffer.length, null); 
    return new String(lpBuffer, 0, lenW); 
    } 

    public static void main(String[] args) throws IOException { 
    String from = ".\\from.txt"; 
    String to = ".\\to.txt"; 
    new FileOutputStream(from).close(); 
    if (!Kernel32.INSTANCE.MoveFileW(new WString(from), 
     new WString(to))) { 
     throw new IOException(getLastError()); 
    } 
    } 
} 

EDIT: He editado mi respuesta después de comprobar el código - que estaba equivocado sobre el uso de char [] en la firma - es mejor utilizar WString.

+0

Bien, pero * cómo * llamar a MoveFileW directamente entonces? Como sugiere Matthew Flaschen, o qué? Algunas líneas de código de ejemplo (como cómo usar Native.loadLibrary() etc) serían apreciadas. – Jonik

+0

¿Revisaste mi ejemplo de trabajo? – jitter

+0

¡Gracias por el ejemplo de JNA! Por cierto, ¿cómo buscaría la interfaz MoveFileA (mencionado en la respuesta de jitter)? Simplemente usar "MoveFileA" en lugar de "MoveFileW" no era bueno. Intento mover/cambiar el nombre de un directorio y no pude hacerlo funcionar, aunque no estoy seguro de si eso se debe a MoveFileW u otra cosa. – Jonik

1

Si esto es realmente necesario (renameTo no funciona y está seguro de que MoveFile lo hará), usaría JNA. Parece que la mayoría del trabajo ya está hecho en com.mucommander.file.util. Kernel32.java/Kernel32API.java.

+0

Y no olvide el GetLastError() para obtener una explicación significativa de los movimientos fallidos a diferencia de File.renameTo() – akarnokd

+0

No estoy seguro/MoveFile funcionará, pero podría intentarlo, ya que renombrar Sure no lo hace. Por cierto, los dos archivos que enlazas no encajan perfectamente; Kernel32API.DEFAULT_OPTIONS falta. ¿Qué debería pasar como tercer parámetro a Native.loadLibrary? Lo intento con un mapa vacío y no puedo hacer que funcione; "ClassCastException: $ Proxy0 no se puede convertir en com.sun.jna.Library". – Jonik

+0

¿Has probado mi ejemplo? – jitter

1

Basado en NativeCall library Hice lo siguiente POC Application.

Se utiliza la función de MoveFileAkernel32.dll

Viene muestra de trabajo lo más completo con un run.bat y todos frasco y dlls en su lugar.

mueve el test.txt incluido para test2.txt


Si no te gusta la versión de biblioteca NativeCall hice otra POC Application basado en/resuing en la biblioteca Java Native Access (JNA). Esta vez MoveFileA y MoveFileW se implementan y se demuestran.

+0

¡Gracias! Utilicé NativeCall y pude hacer movimientos rápidos para directorios grandes desde Java (aunque todavía no lo he probado en una situación donde el cambio de nombre a menudo falla), y el código para hacer la llamada es simple. Pero ahora tengo algunas dudas sobre NativeCall.archivo dll: parece torpe si necesita tenerlo siempre en el directorio de trabajo (si estuviera dentro de uno de los archivos jar, se usa de forma transparente para el usuario de la API, insertar la lib sería más fácil) – Jonik

+0

Como no le gusta la variante NativeCall también hice una aplicación JNA POC. Implementando MoveFileA y MoveFileW – jitter

Cuestiones relacionadas