2014-10-28 40 views
1

有关此目标背后的动机(以及我的努力解决方案)的更多详细信息,请查看我的previous question。我决定把这个问题当作一个新问题,因为我认为它已经发展到足以值得这样做。总之,我打算使用JDOM与NIO结合使用:读取xml文件后阻止文件通道关闭

  1. 获得xml文件的独占文件锁定。
  2. 将文件读入Document对象。
  3. 进行任意更改(锁仍处于活动状态!)。
  4. 将更改写回到xml文件。
  5. 释放文件锁定。

这不过,我得到的是,内置的代码读取XML文件转换成文档对象关闭通道(并因此释放锁),如下所示的问题:

import java.io.*; 
import java.nio.channels.Channels; 
import java.nio.channels.FileChannel; 
import javax.xml.parsers.*; 
import org.w3c.dom.Document; 
import org.xml.sax.SAXException; 

public class Test4{ 
    String path = "Test 2.xml"; 
    private DocumentBuilderFactory dbFactory; 
    private DocumentBuilder dBuilder; 
    private Document doc; 

    public Test4(){ 
     try (final FileChannel channel = new RandomAccessFile(new File(path), "rw").getChannel()) { 
      dbFactory = DocumentBuilderFactory.newInstance(); 
      dBuilder = dbFactory.newDocumentBuilder(); 

      System.out.println(channel.isOpen()); 
      doc = dBuilder.parse(Channels.newInputStream(channel)); 
      System.out.println(channel.isOpen()); 

      channel.close(); 
     } catch (IOException | ParserConfigurationException | SAXException e) { 
      e.printStackTrace(); 
     } 
    } 

    public static void main(String[] args){ 
     new Test4(); 
    } 
} 

输出:

true 
false 

已经通过文档看起来和拖网内置的Java库,我真的很努力,甚至寻找到通道被关闭,更不用说如何防止它关闭。任何指针都会很棒!谢谢。

+0

'DocumentBuilder.parse()'被关闭所提供的输入流。 – EJP 2014-10-28 11:06:16

+0

对不起,这个问题有点误导我,我的意思是我无法弄清楚在DocumentBuilder类中内置的关闭通道的位置以覆盖行为。重写'FilterInputStream'的默认关闭行为(正如接受的答案所做的那样)似乎达到了同样的结果。 – Hungry 2014-10-28 11:14:16

回答

3

一个干净的方式做,这是创建一个FilterInputStream并覆盖close什么都不做:

public Test() { 
    try { 
     channel = new RandomAccessFile(new File(path), "rw").getChannel(); 
     dbFactory = DocumentBuilderFactory.newInstance(); 
     dBuilder = dbFactory.newDocumentBuilder(); 

     System.out.println(channel.isOpen()); 
     NonClosingInputStream ncis = new NonClosingInputStream(Channels.newInputStream(channel)); 
     doc = dBuilder.parse(ncis); 
     System.out.println(channel.isOpen()); 
     // Closes here. 
     ncis.reallyClose(); 
     channel.close(); //Redundant 
    } catch (IOException | ParserConfigurationException | SAXException e) { 
     e.printStackTrace(); 
    } 
} 

class NonClosingInputStream extends FilterInputStream { 

    public NonClosingInputStream(InputStream it) { 
     super(it); 
    } 

    @Override 
    public void close() throws IOException { 
     // Do nothing. 
    } 

    public void reallyClose() throws IOException { 
     // Actually close. 
     in.close(); 
    } 
} 
+0

这正是我要找的,谢谢! – Hungry 2014-10-28 10:59:14

-1

您是否尝试过try-with-ressource陈述?尽管这不是这个功能的主要目的,也许这就是你要找的东西(以自动关闭资源(你的频道)的形式,但只有当你离开相应的尝试块时)

try (final Channel channel = new RandomAccessFile(new File(path), "rw").getChannel()) { 
    // your stuff here 
} catch (IOException ex) { 
    ex.printStackTrace(); 
} 
+0

嗨,谢谢你的回复。不幸的是,我只是试过这个,但它看起来效果不大。这似乎有点清洁,但我可能会保留它! – Hungry 2014-10-28 10:26:53

+1

已更新代码以显示我的测试。 – Hungry 2014-10-28 10:34:50

+0

这会关闭频道。这正是他想要防止的问题。*请阅读这个问题。 – EJP 2014-10-28 11:03:42