J'ai essayé d'utiliser FileLock
pour obtenir un accès exclusif à un fichier afin de :
- le supprimer
- le renommer
- lui écrire
Parce que sous Windows (au moins), il semble que vous ne pouvez pas supprimer, renommer ou écrire dans un fichier qui est déjà utilisé. Le code que j'ai écrit ressemble à quelque chose comme ceci :
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
public abstract class LockedFileOperation {
public void execute(File file) throws IOException {
if (!file.exists()) {
throw new FileNotFoundException(file.getAbsolutePath());
}
FileChannel channel = new RandomAccessFile(file, "rw").getChannel();
try {
// Get an exclusive lock on the whole file
FileLock lock = channel.lock();
try {
doWithLockedFile(file);
} finally {
lock.release();
}
} finally {
channel.close();
}
}
public abstract void doWithLockedFile(File file) throws IOException;
}
Voici quelques tests unitaires qui démontrent le problème. Vous devez avoir Apache commons-io dans votre classpath pour exécuter le 3ème test.
import java.io.File;
import java.io.IOException;
import junit.framework.TestCase;
public class LockedFileOperationTest extends TestCase {
private File testFile;
@Override
protected void setUp() throws Exception {
String tmpDir = System.getProperty("java.io.tmpdir");
testFile = new File(tmpDir, "test.tmp");
if (!testFile.exists() && !testFile.createNewFile()) {
throw new IOException("Failed to create test file: " + testFile);
}
}
public void testRename() throws IOException {
new LockedFileOperation() {
@Override
public void doWithLockedFile(File file) throws IOException {
if (!file.renameTo(new File("C:/Temp/foo"))) {
fail();
}
}
}.execute(testFile);
}
public void testDelete() throws IOException {
new LockedFileOperation() {
@Override
public void doWithLockedFile(File file) throws IOException {
if (!file.delete()) {
fail();
}
}
}.execute(testFile);
}
public void testWrite() throws IOException {
new LockedFileOperation() {
@Override
public void doWithLockedFile(File file) throws IOException {
org.apache.commons.io.FileUtils.writeStringToFile(file, "file content");
}
}.execute(testFile);
}
}
Aucun des tests ne passe. Les deux premiers échouent, et le dernier lève cette exception :
java.io.IOException: The process cannot access the file because another process has locked a portion of the file
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(FileOutputStream.java:247)
at org.apache.commons.io.IOUtils.write(IOUtils.java:784)
at org.apache.commons.io.IOUtils.write(IOUtils.java:808)
at org.apache.commons.io.FileUtils.writeStringToFile(FileUtils.java:1251)
at org.apache.commons.io.FileUtils.writeStringToFile(FileUtils.java:1265)
Il semble que le lock()
place un verrou sur le fichier, ce qui m'empêche ensuite de le renommer, de l'effacer ou de l'écrire. J'ai supposé que le verrouillage du fichier me donnerait un accès exclusif au fichier, de sorte que je pourrais ensuite le renommer/supprimer/écrire sans me soucier de savoir si un autre processus y accède également.
Soit je comprends mal FileLock
ou ce n'est pas une solution appropriée à mon problème.