有關此目標背後動機的更多詳細信息,請參閱我的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