๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๋นˆ ๊ตฌ๋ฉ ์ฑ„์šฐ๊ธฐ

[Kotlin] ํด๋” ์ง€์šฐ๊ธฐ

ํด๋”์™€ ํ•˜์œ„ ํŒŒ์ผ๊นŒ์ง€ ์ง€์šฐ๊ธฐ

    fun delete(directoryPath : String) {

        val dir = File(directoryPath)
        dir.deleteRecursively()
        
    }

 

File.deleteRecursively()์˜ ๋‚ด๋ถ€ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด์•˜๋‹ค.

/**
 * Delete this file with all its children.
 * Note that if this operation fails then partial deletion may have taken place.
 *
 * @return `true` if the file or directory is successfully deleted, `false` otherwise.
 */
public fun File.deleteRecursively(): Boolean = walkBottomUp().fold(true, { res, it -> (it.delete() || !it.exists()) && res })

 

fold ํ•จ์ˆ˜๋Š” ์ด๋Ÿฌํ•˜๋‹ค

public inline fun <T, R> kotlin.sequences.Sequence<T>.fold(initial: R, operation: (R, T) -> R): R { /* compiled code */ }

 

File.deleteRecursively()๋Š” ํด๋” ๋ฐ ํŒŒ์ผ์˜ ์กด์žฌ ์—ฌ๋ถ€๋ฅผ ๋‚ด๋ถ€์—์„œ ์ฒดํฌํ•ด์ฃผ๊ณ  ์žˆ๋‹ค.๐Ÿ‘

 

1) walkBottomUp()์ด Bottom Up ์ˆœ์„œ๋กœ ํŒŒ์ผ Sequence๋ฅผ ๋ฐ˜ํ™˜ํ•ด์ค€๋‹ค.

 

/**
 * Gets a sequence for visiting this directory and all its content in bottom-up order.
 * Depth-first search is used and directories are visited after all their files.
 */
public fun File.walkBottomUp(): FileTreeWalk = walk(FileWalkDirection.BOTTOM_UP)
public fun File.walk(direction: FileWalkDirection = FileWalkDirection.TOP_DOWN): FileTreeWalk =
    FileTreeWalk(this, direction)
/**
 * This class is intended to implement different file traversal methods.
 * It allows to iterate through all files inside a given directory.
 *
 * Use [File.walk], [File.walkTopDown] or [File.walkBottomUp] extension functions to instantiate a `FileTreeWalk` instance.

 * If the file path given is just a file, walker iterates only it.
 * If the file path given does not exist, walker iterates nothing, i.e. it's equivalent to an empty sequence.
 */
public class FileTreeWalk private constructor(
    private val start: File,
    private val direction: FileWalkDirection = FileWalkDirection.TOP_DOWN,
    private val onEnter: ((File) -> Boolean)?,
    private val onLeave: ((File) -> Unit)?,
    private val onFail: ((f: File, e: IOException) -> Unit)?,
    private val maxDepth: Int = Int.MAX_VALUE
) : Sequence<File> {

...

}

 

 

2) fold ์‹คํ–‰

public fun File.deleteRecursively(): Boolean = 
    walkBottomUp().fold(true, { res, it -> (it.delete() || !it.exists()) && res })

 

res๋Š” Boolean ๊ฐ’, it์€ bottom up ์ˆœ์„œ๋กœ ๋ฐ˜ํ™˜๋˜๋Š” File์ด๋‹ค.

fold ์•ˆ์˜ operation์€ walkBottomUp()์œผ๋กœ ๋ฐ›์€ File์˜ ๋ฐ˜ํ™˜์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ์‹คํ–‰๋œ๋‹ค.

 

์ฒซ res ๊ฐ’์€ true. ํด๋” ๋ฐ ํŒŒ์ผ์ด ์กด์žฌํ•˜๋ฉด(!it.exists() -> false) ํŒŒ์ผ์„ delete๋ฅผ ์‹œ์ผœ์ค€๋‹ค. delete๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ด๋ฃจ์–ด์ง€๋ฉด true๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ  ๋‹ค์Œ operation ์‹คํ–‰์ด ์ด๋ฃจ์–ด์ง„๋‹ค.  

 

ํŒŒ์ผ์ด ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ๋‹ค์Œ operation์œผ๋กœ ๋„˜์–ด๊ฐ„๋‹ค. : !it.exists() -> true

 

delete์˜ ๋ฐ˜ํ™˜๊ฐ’์ด false๋กœ ๋‚˜์˜ฌ ๊ฒฝ์šฐ(ํŒŒ์ผ delete๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ด๋ฃจ์–ด์ง€์ง€ ์•Š์€ ๊ฒฝ์šฐ) ๋‹ค์Œ operation์˜ res ๊ฐ’์€ false๋กœ ๋‚˜์˜จ๋‹ค.(it.delete() || !it.exists() -> false) ์ด๋ ‡๊ฒŒ ๋˜๋ฉด ํ›„์†์˜ operation์˜ return ๊ฐ’๋“ค์€ ๊ณ„์† false๋กœ ๋‚˜์˜ฌ ๊ฒƒ์ด๊ณ , ํŒŒ์ผ์˜ ์กด์žฌ ์—ฌ๋ถ€๋ฅผ ์ฐพ๊ฑฐ๋‚˜ ์‚ญ์ œ๋Š” ์ด๋ฃจ์–ด ์ง€์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค.(res -> false) ํ•œ ๋ฒˆ res ๊ฐ’์ด false๊ฐ€ ๋˜๋ฉด ๋‹ค์Œ ํด๋” ๋ฐ ํŒŒ์ผ๋“ค์˜ ์ž‘์—…(delete)์€ ์ด๋ฃจ์–ด์ง€์ง€ ์•Š๋Š” ๊ฒƒ์ด๋‹ค.