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).

È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top