Kotlin Native iOS端FileSeek、getFileLength、readIntoBuffer的正确实现
Kotlin Native iOS端DFU工具文件操作实现修正
现有iOS端代码的核心失效点
- readIntoBuffer入参赋值完全无效:Kotlin函数入参默认是不可重新赋值的
val类型,代码中写buffer = read.toByteArray()仅修改了函数内部的局部引用,完全不会改动调用方传入的原始buffer对象,导致上层始终读不到文件内容。 - EOF行为不符合跨平台约定:当前实现读到文件末尾时,
readDataOfLength返回空NSData,方法返回0,和公共层约定的「文件读完返回-1」、Android端RandomAccessFile.read()的行为不一致,会导致DFU读取流程出现死循环。 - 空指针崩溃风险:
NSFileHandle.fileHandleForReadingAtPath在文件不存在、无访问权限时会返回null,直接强解!!会触发无提示崩溃。 - 文件句柄资源泄漏:原实现未在对象销毁时关闭打开的文件句柄,长期运行会触发iOS系统的文件描述符上限限制。
修正后的iOS端actual实现
actual class PlatformFile actual constructor(filePath: String) { // 打开文件时做非空校验,避免强解崩溃 private val fileHandle = NSFileHandle.fileHandleForReadingAtPath(filePath) ?: error("无法打开目标文件,路径: $filePath") // 对象销毁时自动释放文件句柄 protected fun finalize() { fileHandle.closeFile() } actual fun setPosition(start: Long) { // 从文件头定位到指定偏移,和Android端seek行为完全对齐 fileHandle.seekToFileOffset(start.toULong()) } actual fun getLength(): Long { // 记录当前读指针位置,查询完文件大小后恢复,不影响后续读流程 val currentOffset = fileHandle.offsetInFile val totalSize = fileHandle.seekToEndOfFile() fileHandle.seekToFileOffset(currentOffset) return totalSize.toLong() } actual fun readIntoBuffer(buffer: ByteArray): Int { val requestReadSize = buffer.size.toULong() if (requestReadSize.toLong() <= 0) return 0 val readData = fileHandle.readDataOfLength(requestReadSize) // 读到文件末尾时按公共层约定返回-1 if (readData.length.toLong() == 0L) return -1 // 核心修正:把读取到的字节内容拷贝到传入的原始buffer中,而非替换局部引用 readData.toByteArray().copyInto( destination = buffer, destinationOffset = 0, startIndex = 0, endIndex = readData.length.toInt() ) return readData.length.toInt() } }
实现对齐说明
- 全链路行为和Android端
RandomAccessFile保持一致:定位时从文件头计算偏移、获取文件大小时不移动当前读指针、读到文件末尾返回-1、返回实际读取到的字节数。 - 解决了原实现中buffer无内容写入的核心问题:所有读取操作的写入目标是调用方持有的原始数组对象,不会出现局部引用替换导致的数据丢失。
- 优化了文件大小的获取逻辑:通过文件句柄直接查询总大小,避免了每次调用
NSFileManager遍历文件属性的性能开销,适配DFU流程中频繁读取分片的性能要求。 - 增加了文件句柄的生命周期管理,避免资源泄漏。
注意:该实现兼容Kotlin/Native当前绑定的全版本iOS系统,无需额外适配iOS 13+的新错误处理接口,可直接复用在固件读取的DFU流程中。
内容的提问来源于stack exchange,提问作者Mateusz Krawczuk
相关产品推荐
相关产品推荐

