You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

取消协程会终止文件写入吗?Kotlin协程文件拷贝代码疑问

协程取消后文件拷贝不会自动终止,需手动检查Job状态

直接给结论:你当前的代码中,当取消执行copy函数的Job时,文件拷贝操作不会自动终止,必须在while循环内手动调用ensureActive()检查Job状态,才能让拷贝流程响应取消指令。

原因解析

Kotlin协程的取消是协作式的:只有当协程执行到挂起函数,或者主动触发取消状态检查时,才会响应取消动作。而你代码里的inputStream.read(fileReader)是Java的同步阻塞IO方法,它完全感知不到协程的存在,不会因为Job取消而停止阻塞,会一直执行到读取完成或抛出IO异常,导致拷贝过程无法被中断。

解决办法:在循环中加入取消检查

在while循环内的合适位置调用ensureActive(),这个方法会检查当前协程的Job是否处于活跃状态:如果Job已取消,会立即抛出CancellationException,协程会终止执行并进入finally块关闭流,从而停止拷贝操作。

修改后的代码示例:

suspend fun copy(oldFile: File, newFile: File): Boolean{
    return withContext(Dispatchers.IO) {
        var inputStream: InputStream? = null
        var outputStream: OutputStream? = null
        try {
            val fileReader = ByteArray(4096)
            inputStream = oldFile.inputStream()
            outputStream = FileOutputStream(newFile)
            while (true) {
                // 每次循环前检查协程是否仍活跃
                ensureActive()
                val read: Int = inputStream.read(fileReader)
                if (read == -1) {
                    break
                }
                outputStream.write(fileReader, 0, read)
            }
            outputStream.flush()
            true
        } catch (e: IOException) {
            Log.e(TAG, "${e.message}")
            false
        } catch (e: CancellationException) {
            // 可选:处理取消后的清理工作,比如删除未完成的目标文件
            newFile.delete()
            throw e // 必须重新抛出,让协程框架正常处理取消流程
        } finally {
            inputStream?.close()
            outputStream?.close()
        }
    }
}

补充说明

  • ensureActive()抛出的CancellationException是协程框架的正常取消信号,除非需要做自定义清理(比如删除未完成的文件),否则不需要在普通catch块中捕获;如果捕获了,记得重新抛出,否则协程会认为取消被忽略,继续执行后续逻辑。
  • 若使用Kotlin官方的挂起式IO库(如kotlinx-coroutines-io),其中的挂起版read方法会自动响应协程取消,无需手动调用ensureActive();但如果依赖Java标准库的InputStream,就必须手动添加取消检查。

内容的提问来源于stack exchange,提问作者Diken Mhrz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 15:20:55