Gradle이 파일에 sysout을 쓸 수 없음-java.io.IOException : 파일을 삭제할 수 없음
명령 출력을 일부 파일에 넣으려고합니다. 파일을 쓰기 전에 파일을 삭제하고 쓰기 작업을 수행하고 싶습니다. 다음은 내 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
답변
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
무언가가 파일을 열어두고있을 수 있습니다. 때때로 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 데몬으로 실행 중입니까? 그것없이 시도하십시오. 영구 프로세스이기 때문에 어떤 이유로 해당 파일에 대한 파일 핸들이 열려있을 수 있습니다.