关于文件转换,网上有很多博客都有过介绍,但都过于陈旧。
因此,根据最近的一个Android项目,整合记录一下关于文件类型转换的相关操作,留已备用。
此处相关代码已在Android9、10、11机型上做过相关测试,关于Android相关权限问题不在此做讨论。
先写一下文件创建的函数吧,也是方便后来人使用。
// 创建一个文件, 并在程序退出时自动删除
fun createFile(context: Context, type: String): File {
val fileName = "FILE_" + DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")
.withZone(ZoneOffset.UTC)
.format(Instant.now())
val file = File(context.filesDir, "$fileName.$type")
// println(">>\n>>${file.path} $fileName $type")
// 该行可删去,防止程序退出时自动删除
file.deleteOnExit()
return file
}
首先要注意,URI和Uri是两种类型,不过开发Android时显示图片通常用的是Uri
此外,转换Uri也要根据用途范围分为两种转换方式:
val fileUri = file.toUri()
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
val captureImg = createFile(context, "jpg")
// 此处通过FileProvider.getUriForFile 将File类型转换成Uri类型
val imgUri = FileProvider.getUriForFile(context, "top.sanqii.provider", captureImg!!)
intent.putExtra(MediaStore.EXTRA_OUTPUT, imgUri)
startActivityForResult(intent, captureCode)
为什么要分出两种方式呢,因为Android 7.0以上不再允许在app中把 file://Uri 暴露给其他app,而第一种简单转换方式在本地用仍然是可行的,并未暴露给其它app。
否则就会出现android.os.FileUriExposedException
错误,这时必须使用第二种通用方法,使用它转换得到的Uri是 content:// Uri 的形式。
但需要注意,使用FileProvider需要做额外的配置,具体请参阅Android开发者文档以及相关链接1、相关链接2。其中部分链接可能需要科学上网。
// 存储bitmap到本地文件
fun bitmapToFile(context: Context, bitmap: Bitmap, fileType: String = "jpg"): File {
val file = createFile(context, fileType)
val oStream = file.outputStream()
// 压缩文件
if (fileType == "png") {
bitmap.compress(Bitmap.CompressFormat.PNG, 80, oStream)
} else {
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, oStream)
}
oStream.flush()
oStream.close()
return file
}
// 数据流保存到本地, 可通过调用其Uri供本地使用
fun streamToFile(context: Context, iStream: InputStream, type: String): File {
val fileType = type.subSequence(type.lastIndexOf("/") + 1, type.length) as String
val file = createFile(context, fileType)
val oStream = file.outputStream()
iStream.copyTo(oStream)
oStream.flush()
iStream.close()
iStream.close()
return file
}
在此指出,Android可以直接通过Uri获取其数据的,而不需要将Uri转换得到相应的文件路径。
开发时只需要创建文件,可以直接将Uri的数据存放到该文件中。
activity?.let { activity ->
val file = activity.contentResolver.openInputStream(uri)
?.let { stream ->
val fType = context.contentResolver.getType(uri) ?: "jpg"
// 前面的创建文件的函数,也可以自行创建
streamToFile(context, stream, fType)
}
file?.let { file ->
// do something
}
}
没什么别的,反正安卓兼容性挺让人头疼的。