Android文件类型转换(适用于Android10等)

文件类型转换


前言

关于文件转换,网上有很多博客都有过介绍,但都过于陈旧。
因此,根据最近的一个Android项目,整合记录一下关于文件类型转换的相关操作,留已备用。
此处相关代码已在Android9、10机型上做过相关测试。
在此注意,关于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
    }

二、File转Uri

首先要注意,URI和Uri是两种类型,不过开发Android时显示图片通常用的是Uri

此外,转换Uri也要根据用途范围分为两种转换方式:

  • 该文件仅用于该app(例如展示图片时ImageView所使用的Uri)
val fileUri = file.toUri()
  • 该文件将暴露于该app之外(例如使用Intent时要将文件的Uri传给Extra)
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转File

	// 存储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
    }

四、stream转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
    }

五、Uri转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
	}
}

总结

没什么别的,反正安卓兼容性挺让人头疼的。

上一篇:ccoshf (Numerics) – C 中文开发手册


下一篇:C++ 中关于 输出的重定向