0

我正在尝试使用 openjdk 11 专门锁定 Windows 10 中的文件,但它没有按预期工作。它应该保证只要锁定到位,除了我自己的进程之外,没有进程应该能够编辑/删除/...文件。

我搜索了答案,但它们 a) 很老,b) 使用与我相同的代码并说“这就是它的完成方式”。

下面是一个简单的示例,它创建一个测试文件,并在获取锁后等待 10 秒,然后再读取。非共享锁需要打开选项“WRITE”(否则 tryLock 会引发 UnsupportedOperationException)。

到目前为止的行为:

  • 当我在等待期间删除文件(在 Windows 资源管理器中)时,读取的内容仍会提供文件的原始内容,但在我删除文件的那一刻,文件就从资源管理器概述中消失了
  • 当我在等待期间编辑文件时(例如使用记事本++),编辑器打开文件时没有任何显示的内容,我可以编辑并保存,但之后读取返回 -1 并且文件为空

预期的行为:

  • 对文件的任何其他访问都应返回 Windows 错误(文件正在使用),例如当您打开 Word 文档并尝试将其删除时

我究竟做错了什么?

import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;

public class TestLocking {

    public static void main(String[] args) throws Exception {

        String filename = "testfile.txt";

        Path file = Path.of(filename);
        if (!Files.exists(file)) {
            String content = "foo";
            System.out.format("File '%s' not found - create and fill with '%s'.%n%n", file.toAbsolutePath().toString(),
                    content);
            Files.write(file, content.getBytes(Charset.defaultCharset()));
        }

        FileChannel filechannel = FileChannel.open(file, StandardOpenOption.READ, StandardOpenOption.WRITE);
        FileLock lock = filechannel.tryLock(0, Long.MAX_VALUE, false);

        if (lock == null) {
            System.out.println("File already locked.");
        } else {
            System.out.println("File lock aquired.");
            Thread.sleep(10000);
            System.out.println("reading file..");
            ByteBuffer buffer = ByteBuffer.allocate(1000);
            int readBytes = filechannel.read(buffer);
            System.out.format("read %d bytes.%n", readBytes);
            buffer.flip();
            final byte[] array = new byte[buffer.remaining()];
            buffer.duplicate().get(array);
            String s = new String(array, Charset.defaultCharset());
            System.out.println("---FILE-CONTENT---");
            System.out.println(s);
            System.out.println("---FILE---END-----");
            // unlock
            lock.close();
            System.out.println("File lock released.");
        }
        filechannel.close();
    }
}

edit1:忘记了 channel.close()

4

1 回答 1

0

在 Java 中,可以使用 FileChannel 获得文件锁,它为此提供了两种方法 - lock() 和 tryLock()。

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.OverlappingFileLockException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class FileLockTest {
    private static final Log LOG = LogFactory.getLog(FileLockTest.class);
    private static FileChannel fc;
    private static RandomAccessFile randomAccessFile;
    public FileLockTest(String fileName) throws FileNotFoundException {
        randomAccessFile = new RandomAccessFile(fileName, "rw");
    }
    public void writeToFileWithLock(String data) {
        fc = randomAccessFile.getChannel();
        ByteBuffer buffer = null;
        try (fc; randomAccessFile; FileLock fileLock = fc.tryLock()) {
            if (null != fileLock) {
                buffer = ByteBuffer.wrap(data.getBytes());
                buffer.put(data.toString().getBytes());
                buffer.flip();
                while (buffer.hasRemaining())
                    fc.write(buffer);
            }
        } catch (OverlappingFileLockException | IOException ex) {
            LOG.error("Exception occured while trying to get a lock on File... " + ex.getMessage());
        }
    }
}
于 2020-05-20T13:46:16.513 回答