Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/powerbi/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Xml附加到文件末尾而不是替换文件_Java_Xml_Dom_Channel_File Locking - Fatal编程技术网

Java Xml附加到文件末尾而不是替换文件

Java Xml附加到文件末尾而不是替换文件,java,xml,dom,channel,file-locking,Java,Xml,Dom,Channel,File Locking,有关此目标背后动机的更多详细信息,请参见我的观点。我(再次)决定把这个问题作为一个全新的问题提出,因为我认为它已经发展到值得这样做的程度。作为总结,我打算将JDOM与NIO结合使用,以便: 获取xml文件的独占文件锁定 将文件读入文档对象 进行任意更改(锁定仍处于活动状态!) 将更改写回xml文件 释放文件锁 通过重写FilterInputStream的关闭行为解决了这个问题,现在我有了一个锁定通道,可以使用Transformer.transform()写入该通道。然而,问题是,Transfor

有关此目标背后动机的更多详细信息,请参见我的观点。我(再次)决定把这个问题作为一个全新的问题提出,因为我认为它已经发展到值得这样做的程度。作为总结,我打算将JDOM与NIO结合使用,以便:

  • 获取xml文件的独占文件锁定
  • 将文件读入文档对象
  • 进行任意更改(锁定仍处于活动状态!)
  • 将更改写回xml文件
  • 释放文件锁
  • 通过重写
    FilterInputStream
    的关闭行为解决了这个问题,现在我有了一个锁定通道,可以使用
    Transformer.transform()
    写入该通道。然而,问题是,
    Transformer.Transform
    没有替换原始文件,而是将新文件附加到原始文件的末尾,而不是替换它(参见图)

    问题不在于
    文档
    对象本身,这可以通过打印以下方法返回的字符串(使用
    文档
    对象作为输入)看到:

    public String toXMLString(Node node) {
        try {
            this.removeBlankTextNodes(node);
            StringWriter sw = new StringWriter();
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer transformer = tf.newTransformer();
            transformer.transform(new DOMSource(node), new StreamResult(sw));
            return sw.toString();
        } catch (TransformerException ex) {
            throw new RuntimeException("Error converting to String", ex);
        }
    }
    
    当为同一文件建立新通道并用作
    Transformer.transform()
    结果时,追加问题也不会发生。因此,只有当同一通道用于读写时,才会出现此问题(可能这就是为什么他们在调用
    DocumentBuilder.parse()时选择自动关闭通道的原因)

    我已经彻底检查了文档,找不到任何指定Transformer.transform输出的相关选项(我已经搜索了Transformer/Transformer factory/StreamResult),虽然由于许多类都是抽象的,但我正在努力寻找实际的实现代码。在调试器中检查
    StreamResult
    对象时,实际上似乎append选项设置为false,因此我的主要怀疑是我需要以某种方式清除通道(或相关缓冲区?)在读取操作完成之后。我尝试的最后一件事是使用代码
    channel.open(path.get(path),StandardOpenOption.CREATE)打开除“APPEND”之外的几乎所有选项
    ;这同样没有效果。请注意,我不能只是关闭并重新打开频道,因为这将释放文件锁。任何指针/建议都会很好!代码如下:

    import java.nio.channels.*;
    
    import javax.xml.parsers.*;
    import javax.xml.transform.*;
    import javax.xml.transform.dom.DOMSource;
    import javax.xml.transform.stream.StreamResult;
    import javax.xml.xpath.*;
    
    import org.w3c.dom.*;
    import org.xml.sax.SAXException;
    
    public class Test2{ 
        String path = "...Test 2.xml";
    
        public Test2(){
            Document doc = null;
            DocumentBuilderFactory dbFactory;
            DocumentBuilder dBuilder;
            NodeList itemList;
            Transformer transformer;
            FileChannel channel; 
            Element newElement;
            int prevNumber;
            TransformerFactory transformerFactory ;
            DOMSource source;
            StreamResult result;
            NonClosingInputStream ncis = null;
            try {
                channel = new RandomAccessFile(new File(path), "rw").getChannel();
                FileLock lock = channel.lock(0L, Long.MAX_VALUE, false);
    
                try {
                    dbFactory = DocumentBuilderFactory.newInstance();
                    dBuilder = dbFactory.newDocumentBuilder();
                    ncis = new NonClosingInputStream(Channels.newInputStream(channel));
                    doc = dBuilder.parse(ncis);
                } catch (SAXException | IOException | ParserConfigurationException e) {
                    e.printStackTrace();
                }
                doc.getDocumentElement().normalize();
                itemList = doc.getElementsByTagName("Item");
                newElement = doc.createElement("Item");
                prevNumber = Integer.parseInt(((Element) itemList.item(itemList.getLength() - 1)).getAttribute("Number"));
                newElement.setAttribute("Number", (prevNumber + 1) + "");
                doc.getDocumentElement().appendChild(newElement);
    
    
    
                transformerFactory = TransformerFactory.newInstance();
                transformer = transformerFactory.newTransformer();
                source = new DOMSource(doc);
    
                //channel.open(Paths.get(path), StandardOpenOption.CREATE);
                result = new StreamResult(Channels.newOutputStream(channel));   
    
                transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
                transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
                transformer.setOutputProperty(OutputKeys.METHOD, "xml");
                transformer.setOutputProperty(OutputKeys.INDENT, "yes");
                transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
                transformer.transform(source, result);
                channel.close();
            } catch (IOException | TransformerException e) {
                e.printStackTrace();
            } finally {
                try {
                    ncis.reallyClose();
                } catch (IOException 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();
            }
        }
    
        public static void main(String[] args){
            new Test2();
        }
    }
    

    这种情况几乎肯定会发生,因为您的通道在读取文件后位于文件的末尾

    在执行转换之前,您应该能够通过执行以下操作来解决此问题:

    channel.truncate(0);
    
    这会将文件截断为0大小,并将位置重置为0


    您好,谢谢您的回复。设置频道位置确实如您所说的那样有效,这是正确方向上的一步。不幸的是,我无法删除频道(删除文件没有效果)在不释放相关文件锁的情况下,有没有办法调整频道的大小?@btrs20看起来你应该可以截断文件,我想这应该可以解决问题。你能试试吗?太好了,谢谢!我花了将近一天的时间试图找出如何用20个字符完成一些可能的事情…@btrs20我想我们可以都有这样的日子。:)