7 Stimmen

Was ist der einfachste Weg, eine Windows-Kernel-Funktion von Java aus aufzurufen?

Bei der Suche, wie man das macht, habe ich einige vage Diskussionen über verschiedene Optionen gefunden, wie z.B. JNI vs. JNA, aber nicht viel in Form konkreter Beispiele.

Kontext: Wenn Java's File.renameTo() seine Arbeit nicht erledigen kann (aus welchem Grund auch immer; es ist ein wenig problematisch), würde ich gerne auf diese native Windows-Funktion zurückgreifen, die in kernel32.dll definiert ist (aus dieser Antwort):

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

Also, mit welchem Ansatz auch immer, wie genau würden Sie diese Funktion vom Java-Code aus aufrufen? Ich suche nach dem einfachsten Weg, mit minimalem Einsatz von nicht-Java-Code oder zusätzlichen Schritten (z.B. beim Kompilieren oder Bereitstellen).

7voto

McDowell Punkte 105255

Wenn Sie sich für JNA entscheiden, sollten Sie in Erwägung ziehen, MoveFileW direkt aufzurufen - so sparen Sie sich die Bereitstellung von Konfigurationsinformationen zur Auswahl zwischen Unicode- und ANSI-Aufrufen.

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 nach Überprüfung des Codes bearbeitet - ich lag falsch bei der Verwendung von char[] in der Signatur - es ist besser, WString zu verwenden.

1voto

Matthew Flaschen Punkte 266507

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

1voto

jitter Punkte 52721

Basiert auf der NativeCall Bibliothek habe ich die folgende POC-Anwendung erstellt.

Sie nutzt die MoveFileA Funktion aus kernel32.dll

Es kommt als vollständiges Arbeitsbeispiel mit einer run.bat und allen jar und dll-Dateien an Ort und Stelle.

Es verschiebt die enthaltene test.txt nach test2.txt


Wenn Ihnen die NativeCall Bibliotheksversion nicht gefällt, habe ich eine weitere POC-Anwendung basierend auf der Java Native Access (JNA) Bibliothek erstellt. Dieses Mal sind MoveFileA und MoveFileW implementiert und dargestellt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X