Gradle이 파일에 sysout을 쓸 수 없음-java.io.IOException : 파일을 삭제할 수 없음

Sep 27 2020

명령 출력을 일부 파일에 넣으려고합니다. 파일을 쓰기 전에 파일을 삭제하고 쓰기 작업을 수행하고 싶습니다. 다음은 내 gradle 스크립트입니다.


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이 deletefiles 작업이 시작 되기 전에 어떻게 든 파일에 대한 잠금을 획득한다는 것입니다 . 그렇다면 어떻게 이것을 달성 할 수 있습니까?

편집 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

답변

6 daggett Sep 27 2020 at 20:45

gradle에서 프로젝트 구성 단계에서 다음 줄이 실행되는 문제

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

이는 gradle 작업이 시작되기 전에도 스트림이 생성되고 파일이 잠김을 의미합니다.

이 멋진 구성을 시도하여 문제를 확인하십시오.


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에서 다음 그루비 코드로 바꿀 수 있습니다.

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

1 swpalmer Sep 27 2020 at 03:53

무언가가 파일을 열어두고있을 수 있습니다. 때때로 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 데몬으로 실행 중입니까? 그것없이 시도하십시오. 영구 프로세스이기 때문에 어떤 이유로 해당 파일에 대한 파일 핸들이 열려있을 수 있습니다.