Qual è il modo più semplice per chiamare una funzione del kernel di Windows da Java?
-
05-07-2019 - |
Domanda
Mentre cercavo come farlo, ho trovato alcune vaghe discussioni su diverse opzioni, come JNI vs JNA, ma non molto in termini di esempi concreti.
Contesto: se il File.renameTo ()
di Java non può fare il suo lavoro (per qualsiasi motivo; è un po 'problematico ), vorrei tornare a utilizzare direttamente questa funzione nativa di Windows, che è definita in kernel32.dll (da questa risposta ):
BOOL WINAPI MoveFile(
__in LPCTSTR lpExistingFileName,
__in LPCTSTR lpNewFileName
);
Quindi, usando qualunque approccio, come chiamereste esattamente quella funzione dal codice Java? Sto cercando il modo più semplice, con la quantità minima di codice non Java o passaggi aggiuntivi (ad es. In compilazione o distribuzione).
Soluzione
Se vai con JNA, considera di invocare MoveFileW direttamente - evita di dover fornire informazioni di configurazione per scegliere tra chiamate Unicode e 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: ho modificato la mia risposta dopo aver controllato il codice - mi sono sbagliato a usare char [] nella firma - è meglio usare WString .
Altri suggerimenti
Se questo è veramente necessario (renamePer non funziona e sei sicuro che MoveFile funzionerà), userei JNA . Sembra che la maggior parte del lavoro sia già stata eseguita in com.mucommander.file.util. Kernel32.java / Kernel32API.java .
Basato sulla libreria NativeCall ho fatto quanto segue Applicazione POC .
Utilizza la funzione MoveFileA
da kernel32.dll
Viene fornito come esempio di lavoro completo con un run.bat e tutti i jar e le dll in posizione.
Sposta il test.txt incluso in test2.txt
Se non ti piace la versione della libreria NativeCall, ho fatto un altro Applicazione POC basata su / resending sulla Java Native Access (JNA) . Questa volta MoveFileA
e MoveFileW
sono implementati e dimostrati.