Java:Windows中的通道文件锁定问题

时间:2014-07-21 12:28:17

标签: java windows file-locking

我正在用Java编写一个小程序,将数据写入XML文件。由于有多个用户启动它,我需要在写入之前锁定xml文件。所以我写得那样:

if (new File(path).exists()) {

        try {

            FileChannel channel = new RandomAccessFile(new File(path), "rw")
                    .getChannel();

            java.nio.channels.FileLock lock = channel.lock();

            DocumentBuilderFactory docFactory = DocumentBuilderFactory
                    .newInstance();
            DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
            Document doc = docBuilder.parse(path);

            // Get the root element
            Node economato = doc.getFirstChild();

            NodeList protocolli = doc.getElementsByTagName("numero");

            if (protocolli.getLength() == 0)
                p.setNumero(1);

            else
                p.setNumero(protocolli.getLength()+1);

            Element protocolloNode = doc.createElement("protocollo");
            economato.appendChild(protocolloNode);

            Element protocolloNumero = doc.createElement("numero");
            protocolloNumero.appendChild(doc.createTextNode(Integer
                    .toString(p.getNumero())));
            protocolloNode.appendChild(protocolloNumero);

            Element protocolloData = doc.createElement("data");
            protocolloData.appendChild(doc.createTextNode(p.getData()));
            protocolloNode.appendChild(protocolloData);

            Element protocolloObj = doc.createElement("oggetto");
            protocolloObj.appendChild(doc.createTextNode(p.getOggetto()));
            protocolloNode.appendChild(protocolloObj);

            Element protocolloDest = doc.createElement("destinatario");
            protocolloDest.appendChild(doc.createTextNode(p
                    .getDestinatario()));
            protocolloNode.appendChild(protocolloDest);

            Element protocolloOp = doc.createElement("operatore");
            protocolloOp.appendChild(doc.createTextNode(p.getOperatore()));
            protocolloNode.appendChild(protocolloOp);

            TransformerFactory transformerFactory = TransformerFactory
                    .newInstance();
            Transformer transformer = transformerFactory.newTransformer();

            DOMSource source = new DOMSource(doc);
            StreamResult result = new StreamResult(path);

            transformer.transform(source, result);

            lock.release();
            channel.close();

            JOptionPane.showMessageDialog(this.fatherFrame,
                    "Nuovo protocollo salvato correttamente!");

        } catch (ParserConfigurationException pce) {
            pce.printStackTrace();
        } catch (TransformerException tfe) {
            tfe.printStackTrace();
        } catch (IOException ioe) {
            ioe.printStackTrace();
        } catch (SAXException sae) {
            sae.printStackTrace();
        }
    }

我试图在Linux Debian中启动,一切正常。 相反,如果我在Windows 7中尝试,我会收到此错误:

java.io.IOException: The process cannot access the file because another process has locked a portion of the file
at java.io.FileInputStream.readBytes(Native Method)
a java.io.FileInputStream.read(Unknown Source)
at java.io.BufferedInputStream.fill(Unknown Source)
at java.io.BtufferedInputStream.read(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager$RewindableInputStream.read(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(Unknown Source)
at javax.xml.parsers.DocumentBuilder.parse(Unknown Source)
at it.questura.economato.InsertListener.actionPerformed(InsertListener.java:77)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$200(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)

但是没有其他进程阻止该文件。我只启动了我的程序的一个实例,所以它是唯一的...哪个进程可以锁定文件?

--- --- EDIT 我唯一的解决方案是使用一个名为LOCK的“令牌文件”。你获得了名为LOCK的文件上的通道上的锁,然后你可以在真正的file.xml上读/写...然后你释放LOCK文件上的锁...它似乎工作但我发现它很愚蠢笨。 有什么更好的吗?我还在一个论坛中读到,我可以将文件通道读取()到ByteBuffer中,然后从支持它的byte []创建一个ByteArrayInputStream。然后将流传递给DocumentBuilder。但是当我创建一个ByteBuffer时,在我应该分配它的字节数之前......我怎么能事先知道file.xml有多少字节?

2 个答案:

答案 0 :(得分:1)

请勿使用parse(String path)。使用带有Reader或InputStream的方法并将FileChannel包装在其中。

像这样:Channels.newInputStream(channel)

答案 1 :(得分:0)

FileLock fileLock = null;
FileChannel fileChannel = null;
try {
    fileChannel = FileChannel.open(path, StandardOpenOption.READ,
    StandardOpenOption.WRITE);
    fileLock = fileChannel.tryLock();
    inputStream = Channels.newInputStream(fileChannel);