代码之家  ›  专栏  ›  技术社区  ›  Krishnom

Gradle无法将sysout写入文件-java.io.IOException:无法删除文件

  •  0
  • Krishnom  · 技术社区  · 4 年前

    我正试图将命令的输出放到某个文件中。在写入文件之前,我想删除文件,然后执行写入操作。这是我的毕业剧本

    
    group 'org.example'
    version '1.0-SNAPSHOT'
    
    task deletefiles(type: Delete){
        delete "$projectDir/somefile.txt"
    }
    
    task writefile(type: Exec, dependsOn: deletefiles){
        commandLine 'echo', "Hello World"
        standardOutput = new FileOutputStream("$projectDir/somefile.txt")
    }
    

    但是当我运行writefile任务时,我得到了以下错误

    Execution failed for task ':deletefiles'.
    > java.io.IOException: Unable to delete file 'D:\workspace\code\repo\sample-gradle-mono\somefile.txt'
    

    知道怎么了吗?

    我想有一件事是gradle之前不知怎么地获得了文件锁定 删除文件 任务可以开始了。如果是这样的话,我们如何实现这一目标?

    编辑1: 环境信息-

    ------------------------------------------------------------
    Gradle 6.3
    ------------------------------------------------------------
    
    Build time:   2020-03-24 19:52:07 UTC
    Revision:     bacd40b727b0130eeac8855ae3f9fd9a0b207c60
    
    Kotlin:       1.3.70
    Groovy:       2.5.10
    Ant:          Apache Ant(TM) version 1.10.7 compiled on September 1 2019
    JVM:          11.0.4 (Oracle Corporation 11.0.4+11)
    OS:           Windows 10 10.0 amd64
    
    0 回复  |  直到 4 年前
        1
  •  5
  •   daggett    4 年前

    在gradle中,以下行在项目配置阶段执行的问题

    standardOutput = new FileOutputStream("$projectDir/somefile.txt")
    

    这意味着流在任何gradle任务启动之前就已经创建并锁定了文件。。

    尝试此groovy配置以查看问题:

    
    class MyStream extends FileOutputStream{
        MyStream(String f){ 
            super(f)
            println "write $f stream created" 
        }
    }
    
    task deletefiles(type: Delete){
        println "delete init"
        doFirst{
            println "delete doFirst" //triggered just before deletion
        }
        delete "out.txt"
    }
    
    task writefile(type: Exec, dependsOn: deletefiles){
        println "write init"
        commandLine 'cmd', '/C', 'echo', "Hello World"
        standardOutput = new MyStream("out.txt")
    }
    

    在输出中,您可以看到流是在任务执行之前创建的:

    cmd> gradle writeFile
    
    > Configure project :
    delete init
    write init
    write out.txt stream created
    
    > Task :deletefiles FAILED
    delete doFirst
    
    FAILURE: Build failed with an exception.
    
    * What went wrong:
    Execution failed for task ':deletefiles'.
    > java.io.IOException: Unable to delete file 'out.txt'
    

    修复它 -定义 standardOutput 在执行“Exec”任务之前:

    class MyStream extends FileOutputStream{
        MyStream(String f){ 
            super(f)
            println "write $f stream created" 
        }
    }
    
    task deletefiles(type: Delete){
        println "delete init"
        doFirst{
            println "delete doFirst"
        }
        delete "out.txt"
    }
    
    task writefile(type: Exec, dependsOn: deletefiles){
        println "write init"
        commandLine 'cmd', '/C', 'echo', "Hello World"
        doFirst{
            println "write doFirst"
            standardOutput = new MyStream("out.txt")
        }
        doLast{
            println "write doLast"
        }
    }
    

    输出:

    cmd>gradle writeFile
    
    > Configure project :
    delete init
    write init
    
    > Task :deletefiles
    delete doFirst
    
    > Task :writefile
    write doFirst
    write out.txt stream created
    write doLast
    
    BUILD SUCCESSFUL in 3s
    2 actionable tasks: 2 executed
    

    添加 有些清晰 :

    例如,此任务定义

    task writefile(type: Exec, dependsOn: deletefiles){
        println "write init"
        commandLine 'cmd', '/C', 'echo', "Hello World"
        doFirst{
            println "write doFirst"
            standardOutput = new MyStream("out.txt")
        }
        doLast{
            println "write doLast"
        }
    }
    

    您可以在gradle中替换为以下groovy代码:

    def writefile = project.task( [type: Exec, dependsOn: deletefiles], 'writeFile' )
    
    println "write init"
    writefile.setCommandLine( ['cmd', '/C', 'echo', "Hello World"] )
    
    writefile.getActions().add( 0, {
        //those commands will be executed later when task `writefile` decided to be executed by gradle
        println "write doFirst"
        writefile.standardOutput = new FileOutputStream("out.txt")
    } as Action)
    
    writefile.getActions().add( {
        //those commands will be executed later when task `writefile` decided to be executed by gradle
        println "write doLast" 
    } as Action)
    
    

    可以解释这种行为的官方文件链接:

    https://docs.gradle.org/current/userguide/build_lifecycle.html#sec:settings_file

    https://docs.gradle.org/current/userguide/more_about_tasks.html

        2
  •  1
  •   swpalmer    4 年前

    可能有什么东西使文件保持打开状态。有时,如果IO流没有正确关闭,就会发生这种情况。Gradle文档说,exec任务在进程终止后关闭输出流,所以这应该不是问题。 这可能是Windows上删除时出现的已知问题。例如。: https://carlrice.io/blog/gradle-clean-cant-delete-file-on-windows

    https://github.com/gradle/gradle/issues/9813 (但那是关于文件夹的)

    https://www.eknori.de/2020-09-18/gradle-execution-failed-for-task-appclean-unable-to-delete-file/

    我将使用--debug运行构建,以捕获异常的更多细节。

    你在用Gradle守护进程运行吗?尝试不使用它。由于它是一个持久进程,可能出于某种原因,它有一个打开该文件的文件句柄。