ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java – 在已锁定的文件上打开文件输出流将覆盖它

2019-07-02 20:59:36  阅读:253  来源: 互联网

标签:java concurrency filelock


我遇到了这种情况,并不明白为什么会发生这种情况.有人可以帮我理解nio文件锁的行为.

我使用FileOutputStream打开了一个文件,在使用nio FileLock获取了一个独占锁之后,我在文件中写了一些数据.没有释放锁.在同一个文件上打开另一个FileOutputStream,意图获取一个锁并进行写操作并期望失败.但打开第二个fileoutputstream会覆盖已经锁定的文件,即使在我尝试获取第二个锁之前,该文件也已写入其中.这是预期的吗?我的理解是获取一个独占锁会阻止对锁定文件的任何更改.如何在尝试获取另一个锁时阻止覆盖我的文件? (好像另一个进程试图锁定另一个vm上的同一个文件?)

我试过的示例程序:

        File fileToWrite = new File("C:\\temp\\myfile.txt");
        FileOutputStream fos1 = new FileOutputStream(fileToWrite);
        FileOutputStream fos2 =null;
        FileLock lock1,lock2 =null;
        lock1=fos1.getChannel().tryLock();
        if(lock1!=null){
            //wrote date to myfile.txt after acquiring lock
            fos1.write(data.getBytes());
            //opened myfile.txt again and this replaced the file
            fos2 = new FileOutputStream(fileToWrite);
            //got an overlappingfilelock exception here
            lock2=fos2.getChannel().tryLock();
            fos2.write(newdata.getBytes());
            }

        lock1.release();
        fos1.close();
        if(lock2!=null)
            lock2.release();
        fos2.close();

还尝试将上述内容分成两个程序.执行第1次,在第1次等待时开始第2次.由program1锁定的文件被program2覆盖.以下示例:

PROGRAM1:

    File fileToWrite = new File("C:\\temp\\myfile.txt");
    FileOutputStream fos1 = new FileOutputStream(fileToWrite);
    FileLock lock1 =null;
    lock1=fos1.getChannel().tryLock();
    if(lock1!=null){
        //wrote date to myfile.txt after acquiring lock
        fos1.write(data.getBytes());
        System.out.println("wrote data and waiting");
        //start other program while sleep
        Thread.sleep(10000);
        System.out.println("finished wait");
        }

    lock1.release();
    fos1.close();

程序2:

   File fileToWrite = new File("C:\\temp\\myfile.txt");
    System.out.println("opening 2nd out stream");
    //this overwrote the file
    FileOutputStream fos2 = new FileOutputStream(fileToWrite);
    FileLock lock2 =null;
    lock2=fos2.getChannel().tryLock();
    //lock is null here
    System.out.println("lock2="+lock2);
    if(lock2!=null){
        //wrote date to myfile.txt after acquiring lock
        System.out.println("writing  NEW data");
        fos2.write(newdata.getBytes());
        }

    if(lock2!=null)
        lock2.release();
    fos2.close();

谢谢

解决方法:

获取FileLock后,您将获取整个JVM.这就是为什么FileLock永远不会阻止创建更多FileOutputStream并在同一个JVM中覆盖同一文件的原因–JVM拥有锁.因此,OverlappingFileLockException并不是要告诉你锁是不可用的(这将通过tryLock通过返回null来发出信号),它意味着告诉你存在编程错误:尝试获取已经锁定的锁拥有.

当尝试从不同的JVM访问同一文件时,您偶然发现锁定不一定阻止其他进程写入锁定区域,这只是阻止它们锁定该区域.而且由于您使用的是constructor which truncates existing files,这可能会在您尝试获取锁之前发生.

一种解决方案是使用new FileOutputStream(fileToWrite, true)来避免截断文件.无论您是在同一JVM中打开文件还是在不同进程中打开文件,这都有效.

但是,也许您不想附加到该文件.我想你想在成功获得锁的情况下覆盖.在这种情况下,FileOutputStream的构造函数不会帮助您,因为它们会强制您决定是截断还是追加.

解决方案是放弃旧的API和open the FileChannel directly(至少需要Java 7).然后你有足够的standard open options truncatingappending是不同的.省略两者都允许覆盖而不会急切地截断文件:

try(FileChannel fch=FileChannel.open(fileToWrite.toPath(),
                                     StandardOpenOption.CREATE, StandardOpenOption.WRITE)){
  try(FileLock lock=fch.tryLock()) {
    if(lock!=null) {
      // you can directly write into the channel
      // but in case you really need an OutputStream:
      OutputStream fos=Channels.newOutputStream(fch);
      fos.write(testData.getBytes());
      // you may explicitly truncate the file to the actually written content:
      fch.truncate(fch.position());
      System.out.println("waiting while holding lock...");
      LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(5));
    }
    else System.out.println("couldn't acquire lock");
  }
}

因为它无论如何都需要Java 7,所以您可以使用自动资源管理进行清理.请注意,此代码使用CREATE,这意味着创建文件时已经熟悉的行为(如果不存在),而CREATE_NEW则要求文件不存在.

由于指定的选项,打开操作可能会创建文件但不截断它.所有后续操作仅在获取锁定成功时执行.

标签:java,concurrency,filelock
来源: https://codeday.me/bug/20190702/1359994.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有