验证失败后移动文件(Java)
我们正在验证XML文件,根据验证结果,我们必须将该文件移动到另一个文件夹中 当XML有效时,验证器返回一个值,我们可以毫无问题地移动文件。根据模式,当XML无效时也会发生同样的情况 但是,如果XML格式不正确,验证程序会抛出一个异常,当我们尝试移动文件时,它会失败。我们相信在内存中的某个地方仍然有一个控制文件的句柄。我们尝试在移动文件之前放置System.gc(),这解决了问题,但我们无法将验证失败后移动文件(Java),java,io,saxon,jaxp,Java,Io,Saxon,Jaxp,我们正在验证XML文件,根据验证结果,我们必须将该文件移动到另一个文件夹中 当XML有效时,验证器返回一个值,我们可以毫无问题地移动文件。根据模式,当XML无效时也会发生同样的情况 但是,如果XML格式不正确,验证程序会抛出一个异常,当我们尝试移动文件时,它会失败。我们相信在内存中的某个地方仍然有一个控制文件的句柄。我们尝试在移动文件之前放置System.gc(),这解决了问题,但我们无法将System.gc()作为解决方案 代码如下所示。我们有一个文件对象,从中创建StreamSource。然
System.gc()
作为解决方案
代码如下所示。我们有一个文件对象,从中创建StreamSource。然后将StreamSource传递给验证器。当XML格式不正确时,它抛出SAXException。在异常处理中,我们使用.renameTo()方法移动文件
sc = new StreamSource(xmlFile);
validator.validate(sc);
在我们尝试的接球中
validator.reset();
validator=null;
sc=null;
但是,.renameTo()
仍然无法移动文件。如果我们把System.gc()
放在陷阱中,移动就会成功
有人能告诉我如何在没有System.gc()的情况下对其进行排序吗?
我们使用JAXP和saxon-9.1.0.8作为解析器
非常感谢当您设置
sc=null
时,您向垃圾收集器指示StreamSource文件不再被使用,并且可以被收集。流在其destroy()
方法中自行关闭,因此,如果它们被垃圾收集,它们将被关闭,因此可以在Windows系统上移动(在Unix系统上不会出现此问题)
要在不手动调用GC的情况下解决此问题,只需在sc=null
之前调用sc.getInputStream().close()
。无论如何,这是一个很好的做法
一种常见的模式是进行try。。最后
阻止任何文件句柄的使用,例如
try {
sc = new StreamSource(xmlFile);
// check stuff
} finally {
sc.getInputStream().close();
}
// move to the appropriate place
在Java 7中,您可以改为使用新块。在catch中尝试sc.getInputStream().close()尝试创建
FileInputStream
并将其传递到StreamSource
中,然后在完成后关闭FileInputStream
。通过传入文件
您已经无法控制如何/何时关闭文件句柄。已经给出的三个答案都是正确的:您必须关闭底层流,或者直接调用StramSource,或者获取流并关闭它,或者自己创建流并关闭它
然而,我已经在windows下看到了这种情况,至少三年了:即使你关闭了流,实际上是每个流,如果你试图移动或删除文件,它也会抛出异常。。除非。。。您可以显式调用System.gc()
但是,由于System.gc()不是JVM实际执行一轮垃圾收集的强制要求,而且即使JVM没有被强制删除所有可能的垃圾对象,您也没有真正的方法确保文件可以“立即”删除
我没有一个清楚的解释,我只能想象java.io的windows实现可能会以某种方式缓存文件句柄,直到句柄被垃圾回收后才关闭它
据报道,但我还没有证实,java.nio不受这种行为的影响,因为它对文件描述符有更低级的控制
我过去曾使用过一个解决方案,但这是一个相当棘手的问题,它是:
这是我觉得最烦人、最愚蠢的JRE错误,我无法相信它仍然存在,但不幸的是,我一个月前在windows Vista上发现了它,安装了最新的JRE。相当老,但有些人可能仍然会发现这个问题
文件
关联的流源
在由验证器或转换器处理时似乎会自动分配和释放文件资源。(getInputStream()
返回null
)Files.move(从.toPath()移动到.toPath(),替换现有的、原子的移动);
原子移动的使用这里是关键点。不管是什么原因,这都与Windows锁定文件的恼人行为有关。我认为StreamSource没有关闭方法…?谢谢@stefan,但我看不到StreamSource的.close()方法。我喜欢完整回答问题的方式,以及额外的有用信息,并在原始问题范围之外的伪代码中对琐碎的学究投了否决票。这是一个很棒的社区。你被否决了,因为你提供的第一个和第二个答案/编辑有误导性/错误,而且它仍然令人困惑,因为你仍然在引用不存在的
sc.close()
。谢谢antlersoft,这是有道理的,但我刚刚尝试过,但不幸的是,它不起作用。值得一试——你试过Mike Q的解决方案了吗?它应该能让你更好地控制开口