有关此目标背后动机的更多详细信息,请参阅我的previous question。我(再次)决定完全问这个问题为一个新问题,因为我认为它已经发展到足以值得这样做。总之,我打算使用JDOM与NIO结合使用:Xml附加到文件结尾,而不是替换文件
- 获得xml文件的独占文件锁定。
- 将文件读取到Document对象中。
- 进行任意更改(锁仍处于活动状态!)。
- 将更改写回到xml文件。
- 释放文件锁定。
具有压倒一切的FilterInputStream
的关闭行为解决an issue with reading the xml file via a channel,现在我有我可以写使用Transformer.transform()
锁定的节目。然而,问题是不是替换原始文件,Transformer.Transform
是将新文件追加到原始文件的末尾而不是替换它(请参阅图像)。
的问题是不与Document
对象本身作为可通过打印字符串从以下方法返回,使用所述Document
对象作为输入可以看出:
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()
的result
时,会发生问题。所以,这个问题只出现在同一信道用于读取和写入(也许这就是为什么他们选择调用DocumentBuilder.parse()
时自动关闭通道发生。
我已经相当彻底检查文档,找不到任何相关的选项来指定Transformer.transform的输出(我已经搜索过Transformer/Transformer factory/StreamResult),尽管由于许多类都是抽象的,我正在努力寻找实际的实现代码。看起来append选项设置为false,所以我主要怀疑是在读取操作完成后我需要以某种方式清除通道(或相关的缓冲区?)。我尝试的最后一件事是只用通道打开通道关于除“APPEND”之外使用代码channel.open(Paths.get(path), StandardOpenOption.CREATE)
的每个选项;这再次没有效果。请注意,我不能关闭并重新打开频道,因为这会释放文件锁定。任何指针/建议将会很棒!代码如下:
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();
}
}
嗨,谢谢你的回复。设置通道位置确实如您所说的那样工作,所以朝着正确的方向迈出了一步。不幸的是,我不能删除频道(删除文件没有效果),而没有释放相关的文件锁定,会有一种方法来调整频道的大小吗? – Hungry 2014-10-29 10:18:16
@ btrs20看起来你应该能够截断这个文件,我想应该能够解决这个问题。你可以试试吗? – JLRishe 2014-10-29 10:32:44
这很完美,谢谢!我花了将近一天的时间,努力研究如何在20个字符中做一些可能的事情...... – Hungry 2014-10-29 10:38:36