如何使用 java 锁定文件(如果可能的话)

我有一个 Java 进程,它使用 FileReader 打开一个文件。如何防止另一个(Java)进程打开该文件,或者至少通知第二个进程该文件已经打开?如果文件是打开的(这解决了我的问题) ,这会自动使第二个进程获得异常吗? 还是我必须在第一个进程中用某种标志或参数显式地打开它?

澄清:

我有一个 Java 应用程序,它列出一个文件夹,并打开清单中的每个文件进行处理。它一个接一个地处理每个文件。处理每个文件包括读取它,并根据内容进行一些计算,大约需要2分钟。我还有另一个 Java 应用程序,它可以做同样的事情,但是只能在文件上写。我想要的是能够同时运行这些应用程序,所以场景是这样的。ReadApp 列出文件夹并查找文件 A、 B、 C。它打开文件 A 并开始读取。WriteApp 列出文件夹并查找文件 A、 B、 C。它打开文件 A,看到它是打开的(通过异常或其他方式) ,并进入文件 B。 ReadApp 完成文件 A 并继续到文件 B。它看到它是开放的,并继续到 C。至关重要的是,当 ReadApp 读取相同的文件时,WriteApp 不要进行写操作,反之亦然。它们是不同的过程。

178251 次浏览

如果你可以使用 Java NIO(JDK 1.4或更高版本) ,那么我认为你正在寻找 java.nio.channels.FileChannel.lock()

Lock ()

您可能需要 FileChannel. lock。

try (
FileInputStream in = new FileInputStream(file);
java.nio.channels.FileLock lock = in.getChannel().lock();
Reader reader = new InputStreamReader(in, charset)
) {
...
}

(免责声明: 代码未编译,当然也未测试。)

请注意 文件锁的 API 文档中题为“平台依赖性”的部分。

使用随机访问文件,获取它的信道,然后调用 lock ()。输入或输出流提供的通道没有足够的特权来正确锁定。确保在 finally 块中调用 lock ()(关闭文件并不一定释放锁)。

这可能不是你想要的,但是为了从另一个角度解决问题... ..。

这两个 Java 进程是否希望访问同一应用程序中的同一文件?也许您可以通过一个单一的、同步的方法(或者更好的方法,使用 JSR-166)过滤对文件的所有访问?这样,您就可以控制对文件的访问,甚至可以控制队列访问请求。

不要使用 java.io包中的类,而是使用 java.nio包。后者有一个 FileLock类。可以对 FileChannel应用锁。

 try {
// Get a file channel for the file
File file = new File("filename");
FileChannel channel = new RandomAccessFile(file, "rw").getChannel();


// Use the file channel to create a lock on the file.
// This method blocks until it can retrieve the lock.
FileLock lock = channel.lock();


/*
use channel.lock OR channel.tryLock();
*/


// Try acquiring the lock without blocking. This method returns
// null or throws an exception if the file is already locked.
try {
lock = channel.tryLock();
} catch (OverlappingFileLockException e) {
// File is already locked in this thread or virtual machine
}


// Release the lock - if it is not null!
if( lock != null ) {
lock.release();
}


// Close the file
channel.close();
} catch (Exception e) {
}

下面是一个示例代码片段,用于锁定一个文件,直到该文件的进程由 JVM 完成。

 public static void main(String[] args) throws InterruptedException {
File file = new File(FILE_FULL_PATH_NAME);
RandomAccessFile in = null;
try {
in = new RandomAccessFile(file, "rw");
FileLock lock = in.getChannel().lock();
try {


while (in.read() != -1) {
System.out.println(in.readLine());
}
} finally {
lock.release();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}


}

如果使用 winscp 或 ftp 进行传输,可以对 unix 使用这个函数:

public static void isFileReady(File entry) throws Exception {
long realFileSize = entry.length();
long currentFileSize = 0;
do {
try (FileInputStream fis = new FileInputStream(entry);) {
currentFileSize = 0;
while (fis.available() > 0) {
byte[] b = new byte[1024];
int nResult = fis.read(b);
currentFileSize += nResult;
if (nResult == -1)
break;
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("currentFileSize=" + currentFileSize + ", realFileSize=" + realFileSize);
} while (currentFileSize != realFileSize);
}