如何在 Java 中获取 "ShareDenyWrite" 文件锁

How to acquire a "ShareDenyWrite" File Lock in Java

我需要在 Java 中的文件上获取 SharedDenyWrite 锁。 定义为:"Other applications can open the file for reading but not for writing."

这在 Delphi 中是可能的,只需打开一个文件和参数 "fmSharedDenyWrite"。

但我找不到 Java 等价物。

请注意,使用 FileChannel.tryLock 或 lock(0, Long.MAX_VALUE, true) 获得的独占锁会阻止其他程序读取文件。这对我不起作用。

共享锁( lock(0, Long.MAX_VALUE, false) 不会阻止其他程序写入文件。这对我也不起作用。

这样做的目的是阻止 tortoise svn 和 intellij svn 集成在我的应用程序中打开时通过执行 svn 更新来更新文件内容。

虽然独占锁确实会阻止 svn 更新,但它还会在 intellij 和 notepad++ 中将文件显示为空 - 这会导致后续问题。

同事找到的答案如下: 使用 Java Native Access Framework (https://github.com/java-native-access/jna) Win-API 可用于获得正确的锁定。

这会获取一个带有共享读独占写锁的句柄:

 WinNT.HANDLE lockFile = Kernel32.INSTANCE.CreateFile(filename,
        WinNT.GENERIC_READ | WinNT.GENERIC_WRITE,
        WinNT.FILE_SHARE_READ,
        null,
        WinNT.OPEN_ALWAYS,
        WinNT.FILE_ATTRIBUTE_NORMAL,
        null);

并且以下释放锁:

  Kernel32.INSTANCE.CloseHandle(lock);

读取内容Kernel32.INSTANCE.ReadFile可用,写入Kernel32.INSTANCE.WriteFile.

由于默认的 JNA 缺少 GetFileSizeEx、SetFilePointer 和 SetEndOfFile,此接口可用于访问这些方法,以提高文件读写的质量:

package filesystem.jna;

import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.WinNT;
import com.sun.jna.ptr.LongByReference;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;

public interface JnaFileAccess extends StdCallLibrary {
  JnaFileAccess INSTANCE = Native.load("kernel32", JnaFileAccess.class, W32APIOptions.DEFAULT_OPTIONS);

  boolean GetFileSizeEx(WinNT.HANDLE fileHandle, LongByReference size);

  int SetFilePointer(WinNT.HANDLE fileHandle, long DistanceToMove, Pointer DistanceToMoveHigh, int MoveMethod);

  boolean SetEndOfFile(WinNT.HANDLE fileHandle);
}

然后可以这样调用:

将光标设置为文件开头:

JnaFileAccess.INSTANCE.SetFilePointer(fileHandle, 0, null, 0);

写入数据然后设置文件结尾:

JnaFileAccess.INSTANCE.SetEndOfFile(fileHandle);

除了接口之外不需要其他任何东西,它将自身映射到 Win-API