sri
sri

Reputation: 73

How to fix wrong path for FileInputStream and FileDescriptor in kotlin

FILE is created using URI in cacheDir but when i tried to get the path, image is not found, Logged the URI before creating file and able to see proper URI for image file. Now i had created a File in app cache and tried to retrieve the path of image then not getting full image path, Not sure image is created or not here is my code

 val imagesList = data?.extras?.getStringArray(GligarPicker.IMAGES_RESULT)
                if (!imagesList.isNullOrEmpty()) {
                    val arrayList = ArrayList<MultipartBody.Part>()
                    for (i in 0 until imagesList.size) {
                        Log.e("imagesList.item", imagesList[i])
                        val uri = Uri.parse("file://" + imagesList[i].toString())
                        Log.e("URI", uri.toString())
                        val parcelFileDescriptor: ParcelFileDescriptor? =
                            requireContext().contentResolver.openFileDescriptor(uri, "r")
                        val fileDescriptor: FileDescriptor? = parcelFileDescriptor?.fileDescriptor

                        val file = File(
                            requireContext().cacheDir,
                            requireContext().contentResolver.getFileName(uri!!)
                        )
                        Log.e("File", file.path.toString())

                        val inputStream = FileInputStream(fileDescriptor)
                        val outputStream = FileOutputStream(file)
                        inputStream.copyTo(outputStream)

                        // creates RequestBody instance from file

                        val requestFile: RequestBody =
                            RequestBody.create("multipart/form-data".toMediaTypeOrNull(), file)
                        // requireContext().create("multipart/form-data".toMediaTypeOrNull(), file)

                        val body: MultipartBody.Part? =
                            MultipartBody.Part.createFormData("image", file.name, requestFile)

                        if (body != null) {
                            arrayList.add(body)
                        }
                    }

Tried to log the URI and FILEPATH ,Here is details

URI: file:///storage/emulated/0/DCIM/Camera/IMG_20210131_150237.jpg
File: /data/user/0/com.visilogix.smarttrax/cache

Error logs

  Caused by: java.io.FileNotFoundException: /data/user/0/com.visilogix.smarttrax/cache: open failed: EISDIR (Is a directory)
    at libcore.io.IoBridge.open(IoBridge.java:496)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:235)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:186)
    at com.visilogix.smarttrax.ui.performPutAway.GrnLinesFragment.onActivityResult(GrnLinesFragment.kt:283)
    at androidx.fragment.app.FragmentActivity.onActivityResult(FragmentActivity.java:170)
    at android.app.Activity.dispatchActivityResult(Activity.java:8110)
    at android.app.ActivityThread.deliverResults(ActivityThread.java:4838)
    at android.app.ActivityThread.handleSendResult(ActivityThread.java:4886) 
    at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:51) 
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016) 
    at android.os.Handler.dispatchMessage(Handler.java:107) 
    at android.os.Looper.loop(Looper.java:214) 
    at android.app.ActivityThread.main(ActivityThread.java:7356) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) 
 Caused by: android.system.ErrnoException: open failed: EISDIR (Is a directory)
    at libcore.io.Linux.open(Native Method)

Updated code for creating file

  val uri = Uri.parse("file://" + imagesList[i].toString())
                    Log.e("URI", uri.toString())
                    val parcelFileDescriptor: ParcelFileDescriptor? =
                        requireContext().contentResolver.openFileDescriptor(uri, "r")
                    val fileDescriptor: FileDescriptor? = parcelFileDescriptor?.fileDescriptor

                    val uri1 = Uri.parse(imagesList[i].toString())
                    Log.e("File", requireContext().contentResolver.getFileName(uri1!!))
                    val file = File(
                        requireContext().externalCacheDir?.path,
                        requireContext().contentResolver.getFileName(uri1!!)
                    )
                    file.parentFile.mkdir()
                    file.createNewFile()
                    Log.e(
                        "File2",
                        requireContext().contentResolver.getFileName(uri1!!).toString()
                    )

                    val inputStream = FileInputStream(fileDescriptor)
                    val outputStream = FileOutputStream(file)
                    inputStream.copyTo(outputStream)

App is crashing at val outputStream = FileOutputStream(file).

 Caused by: java.io.FileNotFoundException: /storage/emulated/0/Android/data/com.visilogix.smarttrax/cache: open failed: EISDIR (Is a directory)
    at libcore.io.IoBridge.open(IoBridge.java:496)

Upvotes: 1

Views: 1199

Answers (2)

NRUSINGHA MOHARANA
NRUSINGHA MOHARANA

Reputation: 1559

Sending image to php server using Okhttp: First covert all images to byte array and put it in "backupData" list. Then call "backupOneByOne()" method.

private var client: OkHttpClient = OkHttpClient()

init {
    client.setReadTimeout(5, TimeUnit.MINUTES)
    client.setConnectTimeout(5, TimeUnit.MINUTES)
}
val backupData: MutableList<ByteArray> = mutableListOf()

private suspend fun backupOneByOne(currentPosition: Int, byteArray: ByteArray) {
    val backupResponse = doBackupMultiPartData("merchantKey", byteArray)

    when (backupResponse) {
        is ResponseResult.Success -> {
            Log.d("nm==>>", "Menu Item backup successful !!! AND current item position= $currentPosition")
            if (currentPosition < backupData.size - 1) {
                backupOneByOne(currentPosition + 1, backupData[currentPosition + 1])
            } else {
                Log.d("nm==>>", "Backup of all items is done. Current position= $currentPosition")
            }
        }
        is ResponseResult.Error -> {
            Log.d("nm==>>", "Error while backup of Advance table : \n ${backupResponse.msg.errorMsg}")
        }
        else -> {
        }
    }
}
suspend fun doBackupMultiPartData(apiKey: String, imageData: ByteArray?): ResponseResult<ResponseWrapper<String>> {
    val requestBody = MultipartBuilder().type(MultipartBuilder.FORM)
    //requestBody.addFormDataPart("id",2) put other form data fields
    if (imageData != null) {
        requestBody.addFormDataPart(
                "file", "Logo.png", RequestBody.create(
                MediaType.parse(
                        "image/png"
                ), imageData
        )
        )
    }

    val request = Request.Builder()
            .header("api_key", apiKey) // getting api key from backend
            .url("put url here....")
            .post(requestBody.build())
            .build()
    try {
        val result = apiRequest(request)
        Log.d("nm==>>", "Result: $result")
        return if (result != null) {
            val jsonObject = JSONObject(result)
            if (jsonObject.getBoolean("isSuccessful")) {
                ResponseResult.Success(ResponseWrapper("success", null))
            } else {
                ResponseResult.Error(
                        ResponseWrapper(null, "Back end code error: \n $result")
                )
            }
        } else {
            ResponseResult.Error(
                    ResponseWrapper(
                            null, "Getting NULL as result"
                    )
            )
        }
    } catch (jsonException: JSONException) {
        Log.d("nm==>>", "Restore JSON exception::: \n ${jsonException.localizedMessage}")
        return ResponseResult.Error(
                ResponseWrapper(
                        null,
                        "Restore Json Exception"
                )
        )
    } catch (exception: Throwable) {
        //Log.d("nm==>>", "Network exception::: \n ${exception.localizedMessage}")
        return ResponseResult.NoInternet
    }
}

private suspend fun apiRequest(request: Request): String? = suspendCancellableCoroutine { cancellableContinuation ->
    client.newCall(request).enqueue(object : Callback {
        override fun onFailure(request: Request?, e: IOException?) {
            cancellableContinuation.resumeWith(Result.failure(Throwable("API failed.....${e?.localizedMessage}")))
        }

        override fun onResponse(response: Response?) {
            cancellableContinuation.resumeWith(Result.success(response?.body()?.string()))
        }
    })
}
sealed class ResponseResult<out T> {
    object Loading:ResponseResult<Nothing>()
    object Empty:ResponseResult<Nothing>()
    data class Success<T>(val result:T): ResponseResult<T>()
    data class Error<T>(val msg:T): ResponseResult<T>()
    object NoInternet:ResponseResult<Nothing>()
}
data class ResponseWrapper<out T>(val data: T?, val errorMsg: String?)

Upvotes: 1

NRUSINGHA MOHARANA
NRUSINGHA MOHARANA

Reputation: 1559

Using "externalCacheDir" instead of "cacheDir" while creating file might solve the problem.

requireContext().externalCacheDir?.let {
            val file = File(
                    it.path,
                    requireContext().contentResolver.getFileName(uri!!)
            )
            file.createNewFile()

        }

Upvotes: 1

Related Questions