取消协程会终止文件写入吗?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
相关产品推荐
相关产品推荐

