问题
For more detailed information regarding the motivation behind this goal (and my efforts to solve it) view my previous question. I decided to ask this as a new question entirely as I thought that it had evolved sufficiently to merit doing so. As a summary, I intend to use JDOM in combination with NIO in order to:
- Gain an exclusive file lock on an xml file.
- Read the file into a
Document
object. - Make arbitrary changes (with lock still active!).
- Write the changes back to the xml file.
- Release the file lock.
The issue which I am getting however is that the built-in code to read the xml file into a document object closes the channel (and therefore releases the lock), as seen below:
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();
}
}
Output:
true
false
Having looked through the documentation and trawled the built in Java libraries, I am really struggling to even find where the channel is closed, let alone how to prevent it closing. Any pointers would be great! Thanks.
回答1:
One clean way to do this is to create a FilterInputStream
and override the close
to do nothing:
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();
}
}
回答2:
Did you try the try-with-ressource statment? Even though, this is not the main purpose of this feature, maybe that does what you are looking for (in form of auto closing the ressources (your channel), but only when you leave the corresponding try-block)
try (final Channel channel = new RandomAccessFile(new File(path), "rw").getChannel()) {
// your stuff here
} catch (IOException ex) {
ex.printStackTrace();
}
来源:https://stackoverflow.com/questions/26605671/prevent-file-channel-from-closing-after-reading-xml-file