【发布时间】:2015-10-14 21:59:56
【问题描述】:
请考虑以下示例 Java 类(下面的 pom.xml):
package test.filedelete;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import org.apache.commons.io.IOUtils;
public class Main
{
public static void main(String[] args) throws IOException
{
byte[] bytes = "testtesttesttesttesttesttesttesttesttest".getBytes();
InputStream is = new ByteArrayInputStream(bytes);
Path tempFileToBeDeleted = Files.createTempFile("test", "");
OutputStream os = Files.newOutputStream(tempFileToBeDeleted);
IOUtils.copy(is, os);
deleteAndCheck(tempFileToBeDeleted);
// breakpoint 1
System.out.println("\nClosing stream\n");
os.close();
deleteAndCheck(tempFileToBeDeleted);
}
private static void deleteAndCheck(Path file) throws IOException
{
System.out.println("Deleting file: " + file);
try
{
Files.delete(file);
}
catch (NoSuchFileException e)
{
System.out.println("No such file");
}
System.out.println("File really deleted: " + !Files.exists(file));
System.out.println("Recreating deleted file ...");
try
{
Files.createFile(file);
System.out.println("Recreation successful");
}
catch (IOException e)
{
System.out.println("Recreation not possible, exception: " + e.getClass().getName());
}
}
}
我写入 FileOutputStream 并尝试在之后删除文件而不先关闭 Stream。这是我最初的问题,当然是错误的,但它会导致一些奇怪的观察结果。
当您在 Windows 7 上运行 main 方法时,它会产生以下输出:
Deleting file: C:\Users\MSCHAE~1\AppData\Local\Temp\test6100073603559201768
File really deleted: true
Recreating deleted file ...
Recreation not possible, exception: java.nio.file.AccessDeniedException
Closing stream
Deleting file: C:\Users\MSCHAE~1\AppData\Local\Temp\test6100073603559201768
No such file
File really deleted: true
Recreating deleted file ...
Recreation successful
- 为什么第一次调用 Files.delete() 没有抛出异常?
- 为什么以下对 Files.exist() 的调用返回 false?
- 为什么不能重新创建文件?
关于最后一个问题,我注意到当您在断点 1 处停止时,该文件在资源管理器中仍然可见。当您终止 JVM 时,无论如何该文件都会被删除。关闭流后 deleteAndCheck() 按预期工作。
在我看来,在关闭流之前删除不会传播到操作系统,并且文件 API 没有正确反映这一点。
有人能准确解释一下这里发生了什么吗?
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>filedelete</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
</dependencies>
</project>
更新说明
如果流被关闭并且 Files.delete() 被调用 - 最后一个操作触发 - 或者如果 Files.delete() 在没有关闭流的情况下被调用并且 JVM 被终止,则文件在 Windows 资源管理器中消失.
【问题讨论】:
-
它是什么操作系统?如果是类Unix,可以试试打印父目录的权限吗?
-
顺便说一句,你可以直接使用
Files.copy()将InputStream的内容复制到Path中;不需要 IOUtils -
尝试在
Files.delete(file);上设置一个断点,然后跳过它。在那一刻,文件是否真的从资源管理器窗口中消失了?我怀疑删除以某种方式成功,但 Windows 保留了该文件,因为有另一个引用打开它。这可能是 Windows 工作方式中的低级别。我不希望在 Posix(例如:Linux)系统上出现同样的情况。 -
查看 dhke 答案的最后两个 cmets。他的,然后是我的。