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

Android 10+如何为MediaStore openOutputStream设置Long类型偏移量?

解决Android 10+中MediaStore大文件下载的int偏移量限制问题

首先要澄清一个关键误解:你提到的write(buffer, 0, byteSize)中的第二个参数是字节数组内部的起始偏移,不是文件的全局写入偏移量。文件的写入位置是由OutputStream自动维护的——每次写入后,流的指针会自动后移对应字节数,完全不需要手动指定文件的全局偏移。

为什么int参数不会限制2GB以上大文件?

int的最大值是2^31-1(约2.1GB),但这并不意味着不能下载超过2GB的文件。实际开发中,我们只需要控制单次写入的字节数在int范围内即可(比如常用的4KB、1MB、4MB缓冲区),通过多次分块写入来完成大文件的下载,累计的总字节数可以用long类型跟踪,不会出现溢出问题。

优化后的代码实现

下面是针对大文件下载优化后的代码,重点优化了流的安全管理、分块写入逻辑,并加入了总字节数跟踪:

val resolver = contentResolver
val contentValues = ContentValues().apply {
    put(MediaStore.MediaColumns.DISPLAY_NAME, "CuteKitten001")
    put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
    put(MediaStore.MediaColumns.RELATIVE_PATH, "Download/PerracoLabs")
}

val uri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues)
uri?.let { targetUri ->
    // 使用use函数自动管理OutputStream的关闭,避免资源泄漏
    resolver.openOutputStream(targetUri)?.use { outputStream ->
        var totalBytesWritten: Long = 0
        hiper.get("https://httpbin.org/image", isStream = true)
            .ifException { e -> Log.d(TAG, "Exception: ${e?.message}") }
            .ifFailed { response -> Log.d(TAG, "Failed") }
            .ifStream { buffer, byteSize ->
                buffer?.let {
                    // 确保byteSize在int范围内(实际hiper返回的buffer块大小不会超过int上限)
                    outputStream.write(it, 0, byteSize)
                    totalBytesWritten += byteSize
                    Log.d(TAG, "Written $totalBytesWritten bytes so far")
                } ?: run {
                    outputStream.flush()
                    Log.d(TAG, "Done. Total bytes: $totalBytesWritten")
                }
            }
            .finally { response -> Log.d(TAG, response.text.toString()) }
    } ?: run {
        Log.d(TAG, "Failed to open output stream")
    }
} ?: run {
    Log.d(TAG, "Failed to create media store entry")
}

关键注意事项

  • 流的安全关闭:使用Kotlin的use函数可以自动关闭OutputStream,避免因异常导致的资源泄漏。
  • 缓冲区大小控制:确保单次写入的byteSize始终在int范围内——大多数网络库返回的缓冲区块大小(比如8KB、16KB)都远小于int的上限,所以不需要额外处理。
  • 权限检查:在Android 10+中,使用MediaStore下载到公共目录不需要WRITE_EXTERNAL_STORAGE权限,但如果是Android 9及以下版本,仍需申请该权限。
  • 异常处理:建议在写入过程中加入更多异常捕获逻辑(比如IO异常),避免因写入失败导致的文件损坏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 13:19:07