2009-06-16 6 views
7

Bei der Suche nach dem, wie ich dies tun soll, fand ich eine vage Diskussion über verschiedene Optionen, wie JNI vs JNA, aber nicht viel in der Art von konkreten Beispielen.Was ist der einfachste Weg, eine Windows-Kernelfunktion von Java aus aufzurufen?

Kontext: Wenn Java File.renameTo() nicht tun kann es die Aufgabe (egal aus welchem ​​Grund, it is a little problematic), würde Ich mag wieder fallen diese native Windows-Funktion direkt verwenden, die in kernel32.dll definiert (from this answer):

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

Also, mit welcher Vorgehensweise, wie genau würden Sie diese Funktion innerhalb von Java-Code aufrufen? Ich suche den einfachsten Weg mit der minimalen Menge an nicht-Java-Code oder zusätzlichen Schritten (z. B. bei der Kompilierung oder Bereitstellung).

Antwort

7

Wenn Sie mit JNA arbeiten, sollten Sie in Erwägung ziehen, MoveFileW direkt aufzurufen - Sie müssen keine Konfigurationsinformationen angeben, um zwischen Unicode- und ANSI-Aufrufen zu wählen.

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: Ich habe meine Antwort bearbeitet, nachdem der Code überprüft - ich war falsch über char [] in der Signatur - es ist besser WString zu verwenden.

+0

Ok, aber * wie * MoveFileW dann direkt aufrufen? Wie Matthew Flaschen vorschlägt, oder was? Ein paar Zeilen Beispielcode (wie Native.loadLibrary() usw.) würde geschätzt werden. – Jonik

+0

Haben Sie mein Arbeitsbeispiel überprüft? – jitter

+0

Danke für das JNA-Beispiel! Übrigens, wie würde die Schnittstelle nach MoveFileA aussehen (in Jitters Antwort erwähnt)? Einfach "MoveFileA" anstelle von "MoveFileW" zu verwenden war nicht gut. Ich versuche wirklich, ein Verzeichnis zu verschieben/umzubenennen, und konnte das nicht damit arbeiten lassen - obwohl ich nicht sicher bin, ob das wegen MoveFileW oder etwas anderem ist. – Jonik

1

Wenn dies wirklich notwendig ist (renameTo funktioniert nicht und Sie sind sicher, MoveFile wird), würde ich JNA verwenden. Es sieht so aus, als ob die meiste Arbeit bereits in com.mucommander.file.util erledigt wurde. Kernel32.java/Kernel32API.java.

+0

Und vergessen Sie nicht die GetLastError(), um eine sinnvolle Erklärung für fehlgeschlagene Bewegungen im Gegensatz zu File.renameTo() – akarnokd

+0

Ich bin nicht/sicher/MoveFile wird funktionieren, aber ich könnte versuchen, als renameTo sicher nicht. Übrigens, die beiden Dateien, auf die Sie verlinken, passen nicht perfekt zusammen; Kernel32API.DEFAULT_OPTIONS fehlt. Was sollten Sie als 3. Parameter an Native.loadLibrary übergeben? Ich versuche es mit einer leeren Karte und kann es nicht zur Arbeit bringen; "ClassCastException: $ Proxy0 kann nicht in com.sun.jna.Library umgewandelt werden" tritt auf. – Jonik

+0

Haben Sie mein Beispiel getestet? – jitter

1

Basierend auf der NativeCall library habe ich folgende POC Application getan.

Es nutzt die MoveFileA Funktion von kernel32.dll

Es kommt als komplette Arbeitsprobe mit einem run.bat und alle Gläsern und dlls an seinem Platz.

Es bewegt sich die mitgelieferte test.txt


test2.txt Wenn Sie die NativeCall Bibliothek Version nicht wie ich eine andere POC Application auf Basis did/resuing auf der Java Native Access (JNA) Bibliothek. Diesmal werden MoveFileA und MoveFileW implementiert und demonstriert.

+0

Danke! Mit NativeCall konnte ich große Verzeichnisse aus Java schnell verschieben (obwohl ich es in der Situation, in der renameTo oft fehlgeschlagen ist, noch nicht ausprobiert habe), und der Code für den Aufruf ist tatsächlich einfach. Aber ich habe jetzt einige Zweifel über den NativeCall.DLL-Datei - es scheint ungeschickt, wenn Sie es immer im Arbeitsverzeichnis haben müssen (wenn es in einem der Gläser, transparent für den Benutzer der API verwendet wurde, wäre das Einbetten der Lib einfacher) – Jonik

+0

Wie Sie nicht mögen In der NativeCall Variante habe ich auch eine JNA POC App gemacht. Implementieren von MoveFileA und MoveFileW – jitter

Verwandte Themen