While searching for how to do this, I found some vague discussion about different options, like JNI vs JNA, but not much in the way of concrete examples.
Context: if Java's File.renameTo()
cannot do it's job (for whatever reason; it is a little problematic), I'd like to fall back to directly using this native Windows function, which is defined in kernel32.dll (from this answer):
BOOL WINAPI MoveFile(
__in LPCTSTR lpExistingFileName,
__in LPCTSTR lpNewFileName
);
So, using whatever approach, how exactly would you call that function from within Java code? I'm looking for the simplest way, with the minimum amount of non-Java code or extra steps (e.g. in compilation or deployment).
If you go with JNA, consider invoking MoveFileW directly - it saves having to provide configuration info to choose between Unicode and ANSI calls.
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: I've edited my answer after checking the code - I was mistaken about using char[] in the signature - it is better to use WString.
If this is really necessary (renameTo doesn't work and you're sure MoveFile will), I would use JNA. It looks like most of the work is already done in com.mucommander.file.util.Kernel32.java/Kernel32API.java.
Based on the NativeCall library I did the following POC Application.
It uses the MoveFileA
function from kernel32.dll
It comes as complete working sample with a run.bat and all jar and dlls in place.
It moves the included test.txt to test2.txt
If you don't like the NativeCall library version I did another POC Application based on/resuing on the Java Native Access (JNA) library. This time MoveFileA
and MoveFileW
are implemented and demonstrated.