繁体   English   中英

使用 java.nio.file.Files.move() 时如何避免 java.nio.file.AccessDeniedException?

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

我的 Java 程序(见下文)有时会在 java.move.nio 方法中因 java.nio.file.AccessDeniedException 而崩溃。

我不明白为什么会抛出这个异常,我现在没有绕过。

下面是一个例外的例子:

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)

这里在“PROJECT0”的“GEN70”上检测到问题,但是,它会有所不同。 For example, here is another run: 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 ...
    }
}

我能做些什么来防止我的程序抛出这个异常?

补充从第一个答案中,我从 Oracle 网站下载了 Oracle JDK 1.8.0_221。 然后,我使用 javac 和 java 命令从 CMD window 编译和运行我的程序。 这是成绩单:

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 相同的问题,没有 eclipse。 我心情不好;-)...

更新:我发现了这个绕过。 它运行良好,但我在生产中的应用程序中感觉不太好。 我已经替换了这两行:

// 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 代)。

我知道这个问题很老了,我没有明确的答案,但有一个怀疑。

我有时会遇到同样的问题,但仅在尝试移动可执行文件(或包含此类文件的文件夹)时,并且当我的计算机忙于做其他事情时,这种情况更常见。 我怀疑(企业级)防病毒软件是罪魁祸首。 有时扫描文件的速度不够快,并且当您的程序尝试移动它时仍然会锁定它。

我也没有找到一个很好的解决方案,并使用与您正在使用的解决方案几乎相同的解决方法。 在这里禁用防病毒软件不是一个选项,因为即使我的公司有例外,我们也必须确保该软件适用于我们的客户,而无需禁用防病毒软件。

AccessDeniedException表明存在权限问题。 您是如何执行程序的,用户是否有权创建 c:/projects 目录并对其进行写入?

一种选择是尝试以管理员用户身份运行您的代码。 这篇文章应该对此有所帮助: https://superuser.com/questions/42537/is-there-any-sudo-command-for-windows

目前,据我所知,只有 Aaron( https://stackoverflow.com/users/1678362/aaron )确实尝试了我在问题中提供的示例 Java 代码(谢谢 Aaron)。 他没有重现这个问题。

我想知道我们的两种设置之间可能有什么区别。 也许我的 Windows 10 是专业的这一事实?

此外,如果其他人可以在他们的机器上尝试小代码示例,我会很高兴......尤其是各种设置,包括 Windows 10 Professional。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM