【问题标题】:Java: issue with channel File lock in WindowsJava:Windows 中的通道文件锁定问题
【发布时间】:2014-07-21 12:28:16
【问题描述】:

我正在用 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)

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

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

【问题讨论】:

    标签: java windows file-locking


    【解决方案1】:

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

    像这样:Channels.newInputStream(channel)

    【讨论】:

    • 我已经尝试了很多次你所说的但我总是得到一些错误......我不擅长使用这些东西,我真的是一个新手。请问可以写代码吗?如果你愿意,请
    • 感谢您的帮助。现在它工作得更好了...无论如何,当它执行 lock.release() 时,我在 sun.nio.ch.FileLockImpl.release(Unknown Source) 处收到此错误...你知道这意味着什么吗?
    • 这是一个 ClosedChannelException
    • 可能是因为之前被InputStream.close()关闭了。最好在 javadocs 中查看
    • 在这种情况下,您需要可以命名为 NocloseInputStreamNocloseOutputStream 的类。网络上有几种实现
    【解决方案2】:
    FileLock fileLock = null;
    FileChannel fileChannel = null;
    try {
        fileChannel = FileChannel.open(path, StandardOpenOption.READ,
        StandardOpenOption.WRITE);
        fileLock = fileChannel.tryLock();
        inputStream = Channels.newInputStream(fileChannel);
    

    【讨论】:

    • 虽然这可能会解决问题中提出的具体问题,但最好解释问题是什么以及您的修复工作的原因,以便您的回答可以帮助遇到类似问题的其他人。
    猜你喜欢
    • 1970-01-01
    • 2019-04-05
    • 2021-06-30
    • 2010-11-11
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多