gpt4 book ai didi

java - 文件锁是如何工作的?

转载 作者:搜寻专家 更新时间:2023-10-30 19:56:57 24 4
gpt4 key购买 nike

我一直在尝试使用 FileLock 获得对文件的独占访问权限,以便:

  • 删除它
  • 重命名
  • 写信给它

因为在 Windows 上(至少)您似乎无法删除、重命名或写入已在使用的文件。我写的代码看起来像这样:

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;
}

下面是一些证明问题的单元测试。您需要在类路径中包含 Apache commons-io 才能运行第三个测试。

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);
}
}

没有一个测试通过。前 2 个失败,最后一个抛出此异常:

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)

似乎 lock() 方法在文件上加了一个锁,然后阻止我重命名/删除/写入它。我的假设是锁定文件会给我独占访问文件的权限,这样我就可以重命名/删除/写入它而不必担心是否有任何其他进程也在访问它。

要么我误解了 FileLock,要么它不是适合我的问题的解决方案。

最佳答案

有关另一个进程的消息仅表示您系统上的某个进程打开了该文件。它实际上并不检查该进程是否恰好与尝试删除/重命名文件的进程相同。在这种情况下,同一程序打开了文件。您已打开它以获取锁。此处的锁几乎没有值(value),尤其是当您为删除或重命名操作执行此操作时。

要执行您想要的操作,您需要锁定目录条目。这在 Java 中不可用,在 Windows 中可能也不可用。这些(删除和插入)操作是原子的。这意味着操作系统负责为您锁定目录和其他文件系统结构。如果另一个进程(或您自己的进程)打开了文件,那么这些操作将失败。如果您试图以独占方式锁定文件(目录条目),而另一个进程(或您自己的进程)打开了该文件,则锁定将失败。没有区别,但尝试锁定只会使操作变得复杂,并且在这种情况下,会使操作变得不可能(也就是说,文件总是在您尝试执行操作之前打开)。

现在写入文件是一个有效的锁定操作。锁定要写入的文件或文件的一部分,然后它将起作用。在 Windows 上,此锁定机制是强制性的,因此另一个打开/文件描述符将无法写入锁定下的任何部分。

编辑

根据 FileChannel.lock 上的 JavaDoc,它与调用 FileChannel.lock(0L, Long.MAXVALUE, false) 相同。这是从第一个字节到最后一个字节的区域的独占锁。

其次,根据 FileLock 上的 JavaDoc

Whether or not a lock actually prevents another program from accessing the content of the locked region is system-dependent and therefore unspecified. The native file-locking facilities of some systems are merely advisory, meaning that programs must cooperatively observe a known locking protocol in order to guarantee data integrity. On other systems native file locks are mandatory, meaning that if one program locks a region of a file then other programs are actually prevented from accessing that region in a way that would violate the lock. On yet other systems, whether native file locks are advisory or mandatory is configurable on a per-file basis. To ensure consistent and correct behavior across platforms, it is strongly recommended that the locks provided by this API be used as if they were advisory locks.

编辑

对于testWrite 方法。公共(public) I/O 静态方法上的 JavaDoc 是稀疏的,但说“如果文件不存在,则将字符串写入创建文件的文件......”并且因为此方法采用 File 而不是打开流,它可能会在内部打开文件。可能它没有打开具有共享访问权限的文件,也没有打开附加访问权限。这意味着现有的打开和锁定(您打开获取锁的 channel )正在阻止该使用。要了解更多信息,您需要获取该方法的源代码并查看它的作用。

编辑

对不起,我纠正了。我检查了 Windows API,文件锁定在 Windows 上是强制性的。这就是写入失败的原因。第一次打开(您的 new RandomAccessFile)并锁定文件。打开写入字符串成功但写入失败,因为另一个打开(文件描述符)在强制排他锁下具有文件的完整范围 - 也就是说,在释放锁之前没有其他文件描述符可以写入文件。

请注意,锁定与文件描述符相关联不是进程或线程。

关于java - 文件锁是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4025721/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com