代码之家  ›  专栏  ›  技术社区  ›  Michael Borgwardt

如何诊断file.delete()返回假/查找未关闭的流?

  •  13
  • Michael Borgwardt  · 技术社区  · 15 年前

    我正在使用第三方jpeg/exif操作库( Mediautil )那使我头痛。我想更改图像的exif数据。为此,我需要将更新后的版本写入临时文件,删除原始文件,然后将临时文件重命名为原始名称。

    我的问题是 File.delete() 呼叫失败并返回 false ,大概是因为库仍然以某种方式打开了它——但是我已经做了在API中所能找到的一切,使它关闭了所有的流。更糟糕的是:问题似乎取决于时间,而发生的单元测试有时会失败,有时不会——但代码是 多线程的。

    奇怪的是,有一个库调用消除了这个问题——但它也删除了exif缩略图,这是我实际上不想要的。看看代码,我绝对看不到它在哪里关闭任何可能保持开放的流。

    有什么办法解决这个问题吗?

    编辑: 这是在WindowsXP,Java 6上。还有一件事:我发现如果我打电话 System.gc() 呼叫前 删除文件() 可能是因为这会触发一些终结器。所以它看起来绝对是一条未封闭的河流。

    4 回复  |  直到 10 年前
        1
  •  5
  •   skaffman    15 年前

    我会在这里寻求一些关于调试器的帮助。快速挖掘 java.io 事实证明 finalize() 候选者在 FileOutputStream . 因此,在其中设置一个断点,运行程序,然后尝试获取 System.gc() 触发 FileOutputStream.finalize() 释放你的流。这应该给你一个答案,看看这是否是你的问题。

    一旦您可以复制它,那么您就需要开始匹配 文件输出流 实例及其终结。一个好的调试器将为每个对象提供内部的JVM对象标识符,因此,如果您可以在这些OID被创建时跟踪它们,并在它们最终确定时跟踪它们,那么希望您能够将键调用与 finalize 有一个新的特定呼叫 new FileOutputStream .

    不过,这可能是一个漫长的过程,这取决于您的应用程序有多复杂。

        2
  •  1
  •   nkatsar    10 年前

    如果您使用的是fileoutputstream,则显式关闭它将允许删除该文件。

    例如,代替:

    File myFile = new File("test.txt");
    myCustomStreamProcess(new FileOutputStream(myFile));
    boolean test = myFile.delete(); //May return false
    

    你应该这样做:

    File myFile = new File("test.txt");
    FileOutputStream fos = new FileOutputStream(myFile);
    myCustomStreamProcess(fos);
    fos.close(); //Allow the document to be deleted afterwards
    boolean test = myFile.delete(); //Should always return true
    
        3
  •  0
  •   Adrian Pronk    15 年前

    为什么不在让库打开之前重命名文件?然后,可以使用Java的文件.DeleTeNeXIT()删除重命名的文件。例如:

     File jpeg = new File("image.jpg");
     File temp = new File(jpeg + ".temp.jpg");
     jpg.renameTo(temp);
     SomeObj result = exifLibrary(temp); // or exifLibrary(new FileInputStream(temp);
     OutputStream jpegStream = new FileOutputStream(jpeg);
     output.write(result.bytes();
     output.close();
     temp.deleteOnExit();
     temp.delete();
    
        4
  •  0
  •   Stephen C    15 年前

    看看代码,我绝对看不到它在哪里关闭任何可能保持开放的流。

    我认为您可能已经确定了真正的问题;即,您正在使用的API通过设计打开了泄漏文件句柄。

    因为这是一个开放源代码库,所以您可以访问源代码。因此,您应该能够确认这一点,并在必要时自行解决。为了成为一个好公民,通过提交一个补丁把你的修复方案贡献给项目。