Pregunta

Mientras buscaba cómo hacer esto, encontré una discusión vaga sobre diferentes opciones, como JNI vs JNA, pero no mucho en el camino de ejemplos concretos.

Contexto: si el File.renameTo () de Java no puede hacer su trabajo (por cualquier razón; es un poco problemático ), me gustaría recurrir directamente al uso de esta función nativa de Windows, que se define en kernel32.dll (de esta respuesta ):

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

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

¿Fue útil?

Solución

Si opta por 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());
    }
  }
}

EDITAR: he editado mi respuesta después de verificar el código; me equivoqué al usar char [] en la firma; es mejor usar WString .

Otros consejos

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

Basado en la biblioteca NativeCall hice lo siguiente Aplicación POC .

Utiliza la función MoveFileA de kernel32.dll

Viene como una muestra de trabajo completa con un run.bat y todos los jar y dlls en su lugar.

Mueve el test.txt incluido a test2.txt


Si no le gusta la versión de la biblioteca NativeCall, hice otra Aplicación POC basada en / saliendo de la biblioteca Java Native Access (JNA) . Esta vez MoveFileA y MoveFileW se implementan y demuestran.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top