Как избежать java.nio.file.AccessDeniedException при использовании java.nio.file.Files.move ()? - PullRequest
0 голосов
/ 24 сентября 2019

Моя Java-программа (см. Ниже) иногда падает с java.nio.file.AccessDeniedException при выполнении метода java.nio.File.move ().

Я не мог понять, почему выбрасывается это исключениеи у меня пока нет обхода.

Вот пример исключения:

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)

Здесь проблема обнаружена на «GEN70» в «PROJECT0», но она меняется.Например, вот еще один запуск: java.nio.file.AccessDeniedException: C: \ PROJECTS \ PROJECT2 \ CHANGES -> C: \ PROJECTS \ PROJECT2 \ GEN33 \ CHANGES

Примечание: перед запуском программы вынеобходимо удалить каталог C: / PROJECTS, если он у вас есть.

Что я могу сделать, чтобы моя программа не выдавала это исключение?

Я запускаю этот код в Windows 10 Enterprise и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

Вот код.Вы можете запустить его как отдельное Java-приложение.Перед запуском убедитесь, что у вас нет каталога C: / PROJECTS.

Я буду удивлен, если выполнение программы завершится без исключения на вашем компьютере.Если это так, повторите попытку ...

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

Что я могу сделать, чтобы моя программа не выдавала это исключение?

COMPLEMENTS Из первых ответов я скачал Oracle JDK1.8.0_221 с веб-сайта Oracle.Затем я использовал команды javac и java для компиляции и запуска моей программы из окна CMD.Вот расшифровка:

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>

Та же проблема со стандартной современной JVM, без затмения.Я плохо себя чувствую ;-) ...

ОБНОВЛЕНИЕ: Я нашел этот обход.Это работает хорошо, но я не чувствую себя хорошо с этим в моем приложении в производстве.Я заменил эти две строки:

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

этим кодом:

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

Он работает на удивление хорошо и позволяет моей программе работать до нормального завершения.Но ... ну ... не так удовлетворительно.В конце счетчик сбоев составляет около 10, иногда меньше, иногда больше, всего 1000 попыток (10 проектов x 100 поколений).

Ответы [ 2 ]

0 голосов
/ 27 сентября 2019

На данный момент, насколько я знаю, только Аарон (https://stackoverflow.com/users/1678362/aaron) пробовал пример кода Java, который я предоставил в своем вопросе (спасибо Аарон). Он не воспроизвел проблему.

Интересно, в чем может быть разница между нашими двумя настройками? Может быть, тот факт, что моя Windows 10 является Профессиональной?

Кроме того, я был бы рад, если бы другие могли попробовать небольшой пример кода на своей машине ...особенно с различными настройками, включая Windows 10 Professional.

0 голосов
/ 24 сентября 2019

AccessDeniedException предполагает наличие проблемы с разрешениями.Как вы выполняете свою программу, и есть ли у пользователя права на создание каталога c: / projects и запись в него?

Один из вариантов - попытаться запустить ваш код как пользователь с правами администратора.Этот пост должен помочь с этим: https://superuser.com/questions/42537/is-there-any-sudo-command-for-windows

...