How to avoid java.nio.file.AccessDeniedException when using java.nio.file.Files.move()?

自古美人都是妖i 提交于 2021-01-28 07:46:47

问题


My Java program (see below) sometimes crashes with a java.nio.file.AccessDeniedException in a java.nio.File.move() method execution.

I could not understand why this exception is thrown and I have no bypass for now.

Here is an example of the exception :

java.nio.file.AccessDeniedException: C:\PROJECTS\PROJECT0\CHANGES -> C:\PROJECTS\PROJECT0\GEN70\CHANGES
    at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:95)
    at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:109)
    at sun.nio.fs.WindowsFileCopy.move(WindowsFileCopy.java:399)
    at sun.nio.fs.WindowsFileSystemProvider.move(WindowsFileSystemProvider.java:299)
    at java.nio.file.Files.move(Files.java:1406)
    at com.ibm.cldt.engine.tool.TestMove.generate(TestMove.java:75)
    at com.ibm.cldt.engine.tool.TestMove.createAndUseProject(TestMove.java:42)
    at com.ibm.cldt.engine.tool.TestMove.main(TestMove.java:25)

Here the problem is detected on "GEN70" of "PROJECT0", but, it varies. For example, here is another run : java.nio.file.AccessDeniedException: C:\PROJECTS\PROJECT2\CHANGES -> C:\PROJECTS\PROJECT2\GEN33\CHANGES

Note : before running the program, you have to delete the directory C:/PROJECTS if you have one.

What can I do to prevent my program from throwing this exception ?

I run this code on Windows 10 Enterprise, and an IBM JRE 1.8.

java version "1.8.0"
Java(TM) SE Runtime Environment (build pwa6480sr4fp5-20170421_01(SR4 FP5))
IBM J9 VM (build 2.8, JRE 1.8.0 Windows 10 amd64-64 Compressed References 20170419_344392 (JIT enabled, AOT enabled)
J9VM - R28_20170419_1004_B344392
JIT  - tr.r14.java_20170419_344392
GC   - R28_20170419_1004_B344392_CMPRSS
J9CL - 20170419_344392)
JCL - 20170420_01 based on Oracle jdk8u131-b11

Here is the code. You can run it as Java standalone application. Before launching, check that you do not have a C:/PROJECTS directory.

I will be surprised if the program execution ends without exception on your machine. If that is the case, please retry ...

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class TestMove
{
    private static final String PROJECTS_ROOT = "C:/PROJECTS";
    private static final int NUMBER_OF_PROJECTS = 10;
    private static final int NUMBER_OF_GENERATIONS = 100;
    private static final int NUMBER_OF_CHANGES = 10;


    public static void main( String[] args )
    {
        try
        {
            for ( int project = 0; project < NUMBER_OF_PROJECTS; ++project )
            {
                createAndUseProject( "PROJECT"+project );
            }
        }
        catch ( IOException ioe )
        {
            ioe.printStackTrace();
        }
    }


    private static void createAndUseProject( String projectName ) throws IOException
    {
        Path projectRoot = Paths.get( PROJECTS_ROOT, projectName );
        Files.createDirectories( projectRoot );
        for ( int generation = 0; generation < NUMBER_OF_GENERATIONS; ++generation )
        {
            addNewChanges( projectRoot );
            generate( projectRoot, generation );
        }
    }


    private static final StandardOpenOption[] CREATE_APPEND =
        new StandardOpenOption[] { StandardOpenOption.CREATE, StandardOpenOption.APPEND };


    private static void addNewChanges( Path projectRoot ) throws IOException
    {
        Path changesDir = projectRoot.resolve( "CHANGES" );
        Files.createDirectory( changesDir );
        String newLine = System.lineSeparator();
        Path changesLogFile = changesDir.resolve( "changes.log" );
        try ( BufferedWriter changesWriter = Files.newBufferedWriter( changesLogFile, CREATE_APPEND ) )
        {
            for ( int change = 0; change < NUMBER_OF_CHANGES; ++change )
            {
                changesWriter.append( "This is my change number "+ change ).append( newLine );
            }
        }
    }


    private static void generate( Path projectRoot, int generation ) throws IOException
    {
        Path generationDir = projectRoot.resolve( "GEN"+generation );
        Files.createDirectory( generationDir );
        Path projectChangesDir = projectRoot.resolve( "CHANGES" );
        Path generationChangesDir = generationDir.resolve( "CHANGES" );

        // Here is the problem : AccessDeniedException is thrown ... sometimes.
        Files.move( projectChangesDir, generationChangesDir );

        Path changesLogFile = generationChangesDir.resolve( "changes.log" );
        try ( BufferedReader changesReader = Files.newBufferedReader( changesLogFile ) )
        {
            for ( String change = changesReader.readLine(); change != null; change = changesReader.readLine() )
                computeChange( change );
        }
    }


    private static void computeChange( String change )
    {
        // Do whatever needed ...
    }
}

What can I do to prevent my program from throwing this exception ?

COMPLEMENTS From the first answers, I downloaded the Oracle JDK 1.8.0_221 from Oracle website. Then, I used javac and java commands to compile and run my program from a CMD window. Here is the transcript:

Microsoft Windows [Version 10.0.18362.356]
(c) 2019 Microsoft Corporation. All rights reserved.

C:\tmp\Java>dir
 Volume in drive C is Windows
 Volume Serial Number is 8A56-3036

 Directory of C:\tmp\Java

09/24/2019  06:57 PM    <DIR>          .
09/24/2019  06:57 PM    <DIR>          ..
09/24/2019  06:54 PM             2,678 TestMove.java
               1 File(s)          2,678 bytes
               2 Dir(s)  353,415,393,280 bytes free

C:\tmp\Java>"C:\Program Files\Java\jdk1.8.0_221\bin\javac" TestMove.java

C:\tmp\Java>"C:\Program Files\Java\jdk1.8.0_221\bin\java" TestMove
java.nio.file.AccessDeniedException: C:\PROJECTS\PROJECT0\CHANGES -> C:\PROJECTS\PROJECT0\GEN97\CHANGES
        at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:83)
        at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
        at sun.nio.fs.WindowsFileCopy.move(WindowsFileCopy.java:387)
        at sun.nio.fs.WindowsFileSystemProvider.move(WindowsFileSystemProvider.java:287)
        at java.nio.file.Files.move(Files.java:1395)
        at TestMove.generate(TestMove.java:73)
        at TestMove.createAndUseProject(TestMove.java:40)
        at TestMove.main(TestMove.java:23)

C:\tmp\Java>

Same problem with a standard up-to-date JVM, an no eclipse. I feel bad ;-) ...

UPDATE : I have found this bypass. It works well, but I do not feel good with it in my app in production. I have replaced those two lines :

// Here is the problem : AccessDeniedException is thrown ... sometimes.
Files.move( projectChangesDir, generationChangesDir );

With this code:

while ( true )
{
    try
    {
        Files.move( projectChangesDir, generationChangesDir );
        break;
    }
    catch ( IOException ioe ) { ++failures; }
}

It works suprisingly well and makes it possible for my program to run until its normal end. But ... well ... not so satisfactory. At the end failures counter is around 10, sometimes less, sometimes more, for a total of 1000 attempts (10 projects x 100 generations).


回答1:


I know this question is rather old, and I don't have a clear answer, but a suspicion.

I'm having they same problem sometimes, but only when trying to move executable files (or folders containing such), and it happens more often when my computer is busy doing other stuff. My suspicion is that an (corporate level) antivirus software is the culprit. Sometimes it isn't fast enough to scan the file and still has a lock on it when your program tries to move it.

I also didn't find a nice solution, and use a practically identical workaround to the one you are using. Disabling the antivirus isn't an option here, because even if I get an exception from my company, we also have to ensure the software works for our costumers without the need disable antivirus.




回答2:


AccessDeniedException suggests there is a permissions problem. How are you executing your program, and does the user have permissions to create the c:/projects directory, and write to it?

One option would be to try running your code as an admin user. This post should help with that: https://superuser.com/questions/42537/is-there-any-sudo-command-for-windows




回答3:


For now, as far as I know, only Aaron (https://stackoverflow.com/users/1678362/aaron) did try the sample Java code I provided in my question (thank you Aaron). He did not reproduce the issue.

I wonder what could be the difference between our two setups. Maybe the fact that my Windows 10 is a Professional one ?

Also, I would be happy if others can try the small code sample on their machine ... especially with various setups, including Windows 10 Professional.



来源:https://stackoverflow.com/questions/58083707/how-to-avoid-java-nio-file-accessdeniedexception-when-using-java-nio-file-files

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!