Android Compose中向共享存储读写二进制文件的实现方法
Jetpack Compose 二进制文件读写(导出/导入)实现方案
针对你需要的用户可见、支持跨设备传输的二进制文件读写需求,当前Android的最优方案是基于存储访问框架(SAF),也就是你已经用到的ACTION_CREATE_DOCUMENT/ACTION_OPEN_DOCUMENT配合ContentResolver操作,无需申请传统的存储权限,完全符合Android 10+的存储政策。
一、完善导出(写入二进制数据)逻辑
你现有的代码已经能唤起文件选择器创建空白文件,接下来只需在拿到文件Uri后,通过ContentResolver写入二进制数据:
@Composable fun ExportBinaryScreen(context: Context = LocalContext.current) { var pickedUri by remember { mutableStateOf<Uri?>(null) } // 替换成你的实际二进制数据 val sampleBinaryData = byteArrayOf(0x01, 0x02, 0x03, 0x04, 0x05) val exportLauncher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> pickedUri = result.data?.data?.also { uri -> try { context.contentResolver.openOutputStream(uri)?.use { outputStream -> outputStream.write(sampleBinaryData) Toast.makeText(context, "导出成功", Toast.LENGTH_SHORT).show() } } catch (e: IOException) { e.printStackTrace() Toast.makeText(context, "导出失败:${e.message}", Toast.LENGTH_SHORT).show() } } } Column(modifier = Modifier.padding(16.dp)) { Button( onClick = { val intent = Intent(Intent.ACTION_CREATE_DOCUMENT) .apply { addCategory(Intent.CATEGORY_OPENABLE) type = "application/octet-stream" // 二进制文件通用MIME类型 putExtra(Intent.EXTRA_TITLE, "export.dat") } exportLauncher.launch(intent) } ) { Text("导出二进制文件") } } }
二、实现导入(读取二进制数据)逻辑
用ACTION_OPEN_DOCUMENT唤起文件选择器,选择已有的二进制文件后读取数据:
@Composable fun ImportBinaryScreen(context: Context = LocalContext.current) { var importedData by remember { mutableStateOf<ByteArray?>(null) } val importLauncher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> result.data?.data?.also { uri -> try { context.contentResolver.openInputStream(uri)?.use { inputStream -> importedData = inputStream.readBytes() Toast.makeText(context, "导入成功,数据长度:${importedData?.size}字节", Toast.LENGTH_SHORT).show() } } catch (e: IOException) { e.printStackTrace() Toast.makeText(context, "导入失败:${e.message}", Toast.LENGTH_SHORT).show() } } } Column(modifier = Modifier.padding(16.dp)) { Button( onClick = { val intent = Intent(Intent.ACTION_OPEN_DOCUMENT) .apply { addCategory(Intent.CATEGORY_OPENABLE) type = "application/octet-stream" } importLauncher.launch(intent) } ) { Text("导入二进制文件") } importedData?.let { data -> Text( text = "导入的数据(十六进制):${data.joinToString(" ") { "%02X".format(it) }}", modifier = Modifier.padding(top = 16.dp) ) } } }
三、关键注意事项
- 权限处理:Android 10(API 29)及以上无需申请
WRITE_EXTERNAL_STORAGE或READ_EXTERNAL_STORAGE权限,SAF操作通过系统授权的Uri完成,符合系统安全规范。 - 持久化访问权限:如果需要在应用重启后仍能访问已选择的文件,可在拿到Uri后调用:
权限会被持久化到应用的权限列表中,无需重复选择。context.contentResolver.takePersistableUriPermission( uri, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION ) - 流的安全关闭:使用
use函数自动管理输入/输出流的生命周期,避免资源泄漏。 - 自定义MIME类型:如果你的二进制数据有专属格式,可替换
application/octet-stream为自定义MIME类型(比如application/vnd.yourcompany.yourapp),不影响读写,但能帮助系统识别文件类型。
内容的提问来源于stack exchange,提问作者Fergusmac
相关产品推荐
相关产品推荐

