128

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

澄清:

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

4

8 回答 8

119

FileChannel.lock 可能是您想要的。

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

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

请注意FileLock的 API 文档中标题为“平台依赖项”的部分。

于 2008-09-24T16:20:47.403 回答
63

不要使用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) {
    }
于 2012-01-26T15:20:33.737 回答
17

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

FileChannel.lock()

于 2008-09-24T16:13:36.577 回答
8

java.nio.channels.FileLockjava.nio.channels.FileChannel结合使用

于 2008-09-24T16:14:07.467 回答
5

这可能不是您要寻找的,而是为了从另一个角度解决问题....

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

于 2008-09-25T03:48:21.743 回答
3

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

于 2008-09-25T03:40:36.537 回答
1

下面是一个示例代码片段,用于锁定文件,直到它的进程由 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();
        }
    }

}
于 2017-05-24T03:57:39.147 回答
1

如果您使用 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);
    }
于 2020-08-12T15:44:04.847 回答