首页 > 解决方案 > 我们如何使用 Kotlin for Android 从 InputStream 中保存任何类型的文件?

问题描述

语境:

我的项目是在 WiFi P2P/WiFi Direct 领域。我找到并遵循了一些有用的教程和问题,并且有一个可以在手机之间发送图像的工作应用程序。打开一个套接字并将一个 OutputStream 发送到另一个设备。设备 2 接收流并且必须采用 mime 类型才能压缩并保存到文件。*

编辑:*只需压缩图像,但需要知道文件类型才能将其保存到存储中。

我现在想打开此功能以传输任何(常见)类型的文件,并让其他设备愉快地接收它并将其存储在适当的位置(或者全部下载可能会使它更简单)。

我的问题:

我可以使用什么来确定作为 InputStream 传入的所有(图像、文本、日历事件、联系人、视频)文件的 MIME 类型。

当前代码尝试:

我尝试使用BitmapFactory.decodeStream()来接收选项和 mimeType。这仅适用于图像。

guessContentTypeFromStream()根本没有用,我认为它可能只适合从互联网源流式传输?

任何关于如何在此处使用存储访问框架的说明/提示,或确定 mimeType 的技术,都值得赞赏!

以下是接收端使用的代码:

inner class RxClass: Thread() {
    lateinit var socket: Socket
    lateinit var serverSocket: ServerSocket

    override fun run() {
        try {
            serverSocket = ServerSocket(8888)
            socket = serverSocket.accept()
            //If this line is reached, then a connection has been established between server and client
            Log.d("RECEIVE", "Connection established")

            lateinit var bitmap: Bitmap
            lateinit var inputStream: InputStream
            lateinit var outputStream: OutputStream
            var mimeType: String? = null
            lateinit var path: String

            try {
                inputStream = socket.getInputStream()
                Log.d("RECEIVE", "got InputStream")
                runOnUiThread { Toast.makeText(applicationContext, "Receiving file...", Toast.LENGTH_SHORT).show() }
                //mimeType = guessContentTypeFromStream(inputStream)

                val options = BitmapFactory.Options()
                bitmap = BitmapFactory.decodeStream(inputStream, null, options)!! //TODO: this needs to be for all file types
                mimeType = options.outMimeType
                Log.d("RECEIVE", "Decoded input, Type: $mimeType")
            } catch (e: IOException) {
                e.printStackTrace()
            }

            when(mimeType){ //I was hoping that my attempt would let me know what MIME type was and then here I can act on it differently if neccessary
                "image/jpeg" -> path = Environment.DIRECTORY_PICTURES
                "image/jpg" -> path = Environment.DIRECTORY_PICTURES
                "image/bmp" -> path = Environment.DIRECTORY_PICTURES
                "image/gif" -> path = Environment.DIRECTORY_PICTURES
                "image/png" -> path = Environment.DIRECTORY_PICTURES

                "audio/mpeg" -> path = Environment.DIRECTORY_MUSIC
                "audio/x-wav" -> path = Environment.DIRECTORY_MUSIC

                "video/wav" -> path = Environment.DIRECTORY_MOVIES
                "video/mp4" -> path = Environment.DIRECTORY_MOVIES

                "text/plain" -> path = Environment.DIRECTORY_DOCUMENTS
                "text/html" -> path = Environment.DIRECTORY_DOCUMENTS
                "text/x-vcard" -> path = Environment.DIRECTORY_DOCUMENTS
                "text/x-vcalendar" -> path = Environment.DIRECTORY_DOCUMENTS

                null -> Log.d("RECEIVE", "MIMETYPE is NULL")
            }
            Log.d("RECEIVE", "Save file in location: $path")
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                val resolver: ContentResolver = contentResolver
                val contentValues = ContentValues()
                //contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, name)
                //contentValues.put(MediaStore.Images.Media.MIME_TYPE, mimeType)
                //contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, path)

                val rxUri: Uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)!!
                val inputStream = socket.getInputStream()
                outputStream = resolver.openOutputStream(rxUri)!!
                Log.d("RECEIVE", "Sending File: $rxUri")
                inputStream.copyTo(outputStream)

                if(bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)) {
                    runOnUiThread { Toast.makeText(applicationContext, "File Saved", Toast.LENGTH_SHORT).show() }
                }
                Log.d("RECEIVE", "close streams")
                outputStream.flush()
                outputStream.close()
                inputStream.close()

                runOnUiThread {
                    ReceivedImage.setImageURI(rxUri)
                }

            } else { //Version less than Android Q is not implemented
                
            }
        } catch (e: IOException){
            e.printStackTrace()
        }
    }
}

有用的链接

https://developer.android.com/training/data-storage

https://developer.android.com/training/data-storage/shared/media#add-item

https://developer.android.com/reference/kotlin/android/graphics/BitmapFactory

提前致谢

标签: androidfilekotlininputstreamstorage-access-framework

解决方案


推荐阅读