题
我有一个使用FileReader打开文件的Java进程。如何防止另一个(Java)进程打开此文件,或者至少通知第二个进程该文件已被打开?如果文件是打开的(这解决了我的问题),是否会自动使第二个进程获得异常,或者我是否必须在第一个进程中使用某种标志或参数显式打开它?
澄清:
我有一个Java应用程序,它列出了一个文件夹,并打开列表中的每个文件进行处理。它会逐个处理每个文件。每个文件的处理包括读取它并根据内容进行一些计算,大约需要2分钟。我还有另一个Java应用程序执行相同的操作,而是写入文件。我想要的是能够同时运行这些应用程序,所以场景就是这样的。 ReadApp列出文件夹并找到文件A,B,C。它打开文件A并开始读取。 WriteApp列出文件夹并找到文件A,B,C。它打开文件A,看到它是打开的(通过异常或任何方式)并转到文件B. ReadApp完成文件A并继续到B.它看到它是开放的并且继续到C.在ReadApp读取相同文件时WriteApp不写入是至关重要的,反之亦然。它们是不同的过程。
解决方案
FileChannel.lock可能就是你想要的。
FileInputStream in = new FileInputStream(file);
try {
java.nio.channels.FileLock lock = in.getChannel().lock();
try {
Reader reader = new InputStreamReader(in, charset);
...
} finally {
lock.release();
}
} finally {
in.close();
}
(免责声明:代码未编译,当然未经过测试。)
请注意标题为“平台依赖关系”的部分。在 FileLock的API文档
其他提示
不要使用 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) {
}
如果您可以使用 Java NIO ( JDK 1.4或更高版本),那么我认为您正在寻找 java.nio.channels.FileChannel.lock ()代码>
这可能不是你想要的,而是为了从另一个角度解决问题....
这两个Java进程是否可能要在同一个应用程序中访问同一个文件?也许您可以通过单个同步方法过滤对文件的所有访问(或者更好,使用 JSR-166 )?这样,您就可以控制对文件的访问,甚至可以控制队列访问请求。
使用RandomAccessFile,获取它的频道,然后调用lock()。输入或输出流提供的通道没有足够的权限来正确锁定。一定要在finally块中调用unlock()(关闭文件不一定会解除锁定)。
几年前,当我编写一个需要MacOS / Windows上的多个用户在多个文件中共享相同数据的应用程序时,我发现了同样的问题。 文件锁定在MacOS上不起作用所以我创建了自己的'ioFile'类,它保留了自己的文件访问寄存器 - 打开r / o,打开r / w等,以及谁'拥有'锁。 这是我可以控制使用不同操作系统的不同机器上不同用户访问的唯一方法。
下面是一个示例代码段代码,用于锁定文件,直到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();
}
}
}
如果您将文件访问权限置于synchronized块中,则只有一个线程实例可以进入其中,其他实例将等待,直到一个完成它的工作。
public class FileReader{
public void read() {
synchronized (this) {
//put you file access here
}
}
}
package tips.javabeat.nio.lock;
import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
public class FileLockTest {
public static void main(String[] args) throws Exception {
RandomAccessFile file = null;
FileLock fileLock = null;
try
{
file = new RandomAccessFile("FileToBeLocked", "rw");
FileChannel fileChannel = file.getChannel();
fileLock = fileChannel.tryLock();
if (fileLock != null){
System.out.println("File is locked");
accessTheLockedFile();
}
}finally{
if (fileLock != null){
fileLock.release();
}
}
}
static void accessTheLockedFile(){
try{
FileInputStream input = new FileInputStream("FileToBeLocked");
int data = input.read();
System.out.println(data);
}catch (Exception exception){
exception.printStackTrace();
}
}
您使用java.nio。* API来锁定文件。但是,这并不能保证锁定,这取决于底层操作系统是否支持锁定。 据我所知,像Linux这样的操作系统不支持锁定,因此即使使用这些API也无法锁定