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).
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.