【问题标题】:Trying to create a directory immediately after a successful deleteIfExists throws AccessDenied Exception尝试在成功 deleteIfExists 后立即创建目录会引发 AccessDenied 异常
【发布时间】:2016-09-22 00:12:39
【问题描述】:

我正在尝试创建一个文件,如果存在,则在此之前将其删除。我的问题是,每当我成功删除操作并立即尝试创建相同的文件夹时,它都会因 AccessDenied 而失败。方法描述(对于 deleteIfExists 和 createDirectory)没有提到这种行为,所以我想我做错了什么。

这是代码:

package nio2;
import java.io.*;
import java.nio.file.*;
public class Test{

    public static void main(String[] args)
    {
        Path existing = Paths.get("nio2//alpha//inner.txt"); // already existing
        Path cpytarget = Paths.get("nio2//alphacpy//inner.txt"); // file to be created 
        Path target = Paths.get("nio2//alphacpy");//
        try{
            if(Files.exists(cpytarget))
            {
                Files.list(target).forEach(Test::WrappedDeleteIfExists); // deleting files inside folder
                System.out.println("Deleting the directory if it exists - alphaCpy\t" +  Files.deleteIfExists(target));//deleting
            }
            else
                System.out.println("It does not exist, no need to delete anything");
            System.out.println("Creating alphaCpy\t" + Files.createDirectory(target));//creating
            System.out.println("copying inner.txt to the new directory\t" + Files.copy(existing,cpytarget));
        }catch(IOException e)
        {
            e.printStackTrace();
        }
    }
    public static void WrappedDeleteIfExists(Path in)
    {
        try{
            System.out.println("Deleting files inside the folder\t" + Files.deleteIfExists(in));
        }catch (IOException e)
        {
            e.printStackTrace();
        }
    }

}

所以在成功运行时(没有删除时)。这是输出

It does not exist, no need to delete anything
Creating alphaCpy       nio2\alphacpy
copying inner.txt to the new directory  nio2\alphacpy\inner.txt

如果我在文件夹和文件已经存在时运行它,我会得到异常:

Deleting files inside the folder        true
Deleting the directory if it exists - alphaCpy  true
java.nio.file.AccessDeniedException: nio2\alphacpy
        at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:83)
        at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
        at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
        at sun.nio.fs.WindowsFileSystemProvider.createDirectory(WindowsFileSystemProvider.java:504)
        at java.nio.file.Files.createDirectory(Files.java:674)
        at nio2.Test.main(Test.java:19)

下一次运行再次成功,因为它已经被删除等等。所以问题是导致 AccessDenied 异常的原因是什么?请记住,该文件未打开/未使用,并且相对路径有效。

编辑:好的,我设法纠正了它,但老实说,我仍然无法向自己解释最初的问题。因此,如果有人可以提供帮助,我将不胜感激。我从使用 Stream 转到 File[] 以删除文件夹内的文件。在我这样做之后,它就像一个魅力。

以下是更正后的代码:

public static void main(String[] args) throws InterruptedException
    {
        Path existing = Paths.get("E:/work/Java/Tests/alpha/inner.txt"); // already existing
        Path cpytarget = Paths.get("E:/work/Java/Tests/alphacpy/inner.txt"); // file to be created 
        Path target = Paths.get("E:/work/Java/Tests/alphacpy");//
        File fileTarget = new File("E:/work/Java/Tests/alphacpy");      
        try{
            if(Files.exists(cpytarget))
            {
                WrappedDeleteIfExists(fileTarget.listFiles()); // CHANGED , no longer using Stream<Path> pipeline to go through the file list
                // deleting files inside folder
                System.out.println("Deleting the directory if it exists - alphaCpy\t" +  Files.deleteIfExists(target));//deleting
            }
            else
                System.out.println("It does not exist, no need to delete anything");
            System.out.println(Files.exists(target));

            System.out.println("Creating alphaCpy\t" + Files.createDirectory(target));//creating
            System.out.println("copying inner.txt to the new directory\t" + Files.copy(existing,cpytarget));
        }catch(IOException e)
        {
            e.printStackTrace();
        }
    }
    // CHANGED - using File[] instead of Path
    public static void WrappedDeleteIfExists(File[] in)
    {
        for(int i =0;i<in.length;i++)
        {
            System.out.println("Deleting files inside the folder\t" +in[i].delete());
        }

    }

显然,即使在完成之后,Stream 操作也会以某种方式将其锁定,但这不是我可以关闭的 IO 流(或者它与 Files.list() 一起使用??),所以我该怎么做才能关闭让它与 Stream 一起工作 - 它不是可关闭的东西或试图强制 GC 的东西是有意义的。

【问题讨论】:

  • 如果您在调试器中一次单步执行代码,是否还会看到相同的错误?如果不是,则可能是删除操作在操作系统接受删除后立即返回,但操作系统需要有限的时间(数十到数百毫秒)才能完成目录的删除。如果是这种情况,您将不得不插入一个带有指数回退的重试循环,例如 1 秒。您不能无限期地重试,因为可能存在真正的访问被拒绝情况。
  • 一步一步在调试器中得到相同的结果。还尝试添加 Thread.sleep(5000); ,以便主线程在删除后等待几秒钟。结果没有变化。
  • 为什么要使用双 forward 斜杠。你不应该那样做。尝试单正斜杠。另外,在删除操作后打印出Files.exists(target)的值,看看NIO栈对目录存在的看法。
  • 我也试过了,它返回 false- 不存在。还尝试了单独的硬盘驱动器+ pc重启。谢谢你的斜线。 :)
  • 我没主意了。您可以查看Java bug database

标签: java delete-file access-denied


【解决方案1】:

我注意到一个使用 Files.list(dir) 后跟 Files.deleteIfExists(path) 的程序存在类似问题。在虚拟机退出之前,所有已删除的文件夹都不会从 Windows 资源管理器视图中消失,如果在虚拟机退出之前在 Windows 资源管理器中单击,则会拒绝访问。

我的程序只需在使用后关闭每个 Files.list() 流即可修复,最好使用 try(resource) ... 最后。然后 Windows 资源管理器会立即与每次删除发生同步,而不是等到 VM 退出

try(Stream<Path> str = Files.list(target))
{
    // do your str.forEach() calls with Files.deleteIfExists
}
finally
{
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多