【问题标题】:Java file locking on a network网络上的 Java 文件锁定
【发布时间】:2009-01-06 12:08:25
【问题描述】:

这可能与以前的帖子类似,但我想具体说明在网络上而不是本地上锁定的使用。我想将文件写入共享位置,因此它很可能会在网络上运行(当然是 Windows 网络,也可能是 Mac)。我想防止其他人在写入该文件时读取它的任何部分。这不是一个高度并发的进程,文件通常小于 10MB。

我已经阅读了FileLock 文档和File 文档,对于什么是安全的,什么不是安全的感到有些困惑。我想锁定整个文件,而不是其中的一部分。

我可以使用FileChannel.tryLock(),它在网络上是安全的,还是取决于网络的类型?它是否可以在标准的 Windows 网络上运行(如果有的话)。

如果这样不行,最好是创建一个零字节文件或目录作为锁文件,然后写出主文件。为什么File.createNewFile() 文档说不要使用它来锁定文件?我很欣赏这取决于比赛条件,并不理想。

【问题讨论】:

    标签: java file networking


    【解决方案1】:

    这不能在网络文件系统上可靠地完成。只要您的应用程序是访问该文件的唯一应用程序,最好实现某种协作锁定过程(可能在您打开文件时将锁定文件写入网络文件系统)。但是,不建议这样做的原因是,如果您的进程崩溃或网络出现故障或发生任何其他数量的问题,您的应用程序就会进入令人讨厌的肮脏状态。

    【讨论】:

      【解决方案2】:

      我发现了这个错误报告,它描述了为什么将有关文件锁定的注释添加到 File.createNewFile 文档中。

      http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4676183

      它说:

      如果您在调用 createNewFile 之前将该文件标记为 deleteOnExit 但该文件已经存在,则您可能会删除不是您创建的文件并删除其他人的锁!另一方面,如果你在创建文件之后标记文件,你就会失去原子性:如果程序在文件被标记之前退出,它不会被删除并且锁将被“楔入”。

      因此,看起来不鼓励使用 File.createNewFile() 进行锁定的主要原因是,如果 JVM 在您有机会删除它之前意外终止,您可能会得到孤立的锁定文件。如果您可以处理孤立的锁定文件,那么它可以用作简单的锁定机制。但是,我不推荐错误报告的 cmets 中建议的方法,因为它在读取/写入时间戳值和回收过期锁方面存在竞争条件。

      【讨论】:

        【解决方案3】:

        您可以在要写入的服务器上放置一个空文件。

        当您想写入服务器时,您可以捕获令牌。只有当您拥有令牌时,您才应该写入位于服务器上的任何文件。

        当您准备好进行文件操作或引发异常时,您必须释放令牌。

        帮助类可能看起来像

        private FileLock lock;
        
        private File tokenFile;
        
        public SLTokenLock(String serverDirectory) {
            String tokenFilePath = serverDirectory + File.separator + TOKEN_FILE;
            tokenFile = new File(tokenFilePath);
        }
        
        public void catchCommitToken() throws TokenException {
            RandomAccessFile raf;
            try {
                raf = new RandomAccessFile(tokenFile, "rw"); //$NON-NLS-1$
                FileChannel channel = raf.getChannel();
                lock = channel.tryLock();
        
                if (lock == null) {
                    throw new TokenException(CANT_CATCH_TOKEN);
                }
            } catch (Exception e) {
                throw new TokenException(CANT_CATCH_TOKEN, e);
            }
        }
        
        public void releaseCommitToken() throws TokenException {
            try {
                if (lock != null && lock.isValid()) {
                    lock.release();
                }
            } catch (Exception e) {
                throw new TokenException(CANT_RELEASE_TOKEN, e);
            }
        }
        

        你的操作应该是这样的

        try {
                token.catchCommitToken();
        
                // WRITE or READ to files inside the directory
            } finally {
                token.releaseCommitToken();
            }
        

        【讨论】:

          【解决方案4】:

          与其实施一种锁定策略,这种策略很可能依赖读者遵守您的约定,但不会强迫他们遵守,也许您可​​以将文件写到一个隐藏的或命名模糊的文件中,这样它会有效读者看不见。写入操作完成后,将文件重命名为预期的公共名称。

          缺点是在没有额外 IO 的情况下隐藏和/或重命名可能需要您使用本机操作系统命令,但这样做的过程应该相当简单和确定。

          【讨论】:

            猜你喜欢
            • 2012-07-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-01-15
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多