如何修复 Kotlin 中 FileInputStream 和 FileDescriptor 的错误路径
Posted
技术标签:
【中文标题】如何修复 Kotlin 中 FileInputStream 和 FileDescriptor 的错误路径【英文标题】:How to fix wrong path for FileInputStream and FileDescriptor in kotlin 【发布时间】:2021-05-29 10:02:24 【问题描述】:FILE 是使用 cacheDir 中的 URI 创建的,但是当我尝试获取路径时,找不到图像,在创建文件之前记录了 URI,并且能够看到图像文件的正确 URI。现在我在应用程序缓存中创建了一个文件并尝试检索图像的路径然后没有获得完整的图像路径,不确定图像是否创建这是我的代码
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)
尝试记录 URI 和 FILEPATH ,这里是详细信息
URI: file:///storage/emulated/0/DCIM/Camera/IMG_20210131_150237.jpg
File: /data/user/0/com.visilogix.smarttrax/cache
错误日志
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)
更新了创建文件的代码
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)
应用程序在 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)
【问题讨论】:
该消息告诉您您尝试打开目录而不是文件。可能您在将目录更改为 file.getParentFile().mkdirs(); 之前使用 file.mkdirs() 创建了目录。 @blackapps file.mkdirs() 添加但没有成功 您当然不应该尝试这样做。请重新阅读我的消息并删除目录。或使用其他名称。requireContext().contentResolver.getFileName(uri1!!)
我们看不到那将是哪个文件名或它是否为空。请使用硬编码的文件名。还要告诉 file.getAbsolutePath() 的值。
普通的图像选择器不会提供这样的文件系统路径,而是提供内容方案 uri。但我当然不是那个。您尝试创建的那个。你有问题的那个。
【参考方案1】:
在创建文件时使用“externalCacheDir”而不是“cacheDir”可能会解决问题。
requireContext().externalCacheDir?.let
val file = File(
it.path,
requireContext().contentResolver.getFileName(uri!!)
)
file.createNewFile()
【讨论】:
没有修复它。这是使用 externalCacheDir 的文件路径:/storage/emulated/0/Android/data/com.visilogix.smarttrax/cache 抱歉,我错过了在“requireContext().externalCacheDir”中调用的“getPath()”。调用“requireContext().externalCacheDir.path”创建文件,我得到正确的 URI。 引起:java.io.FileNotFoundException:/storage/emulated/0/Android/data/com.visilogix.smarttrax/cache:打开失败:EISDIR(是一个目录)面临同样的问题更新的变化 在创建文件后尝试使用“file.createNewFile()”,因为没有可用的内容,所以无法创建文件。 请查看。我将其发布为该问题的另一个答案。祝你好运!【参考方案2】:使用 Okhttp 将图像发送到 php 服务器: 首先将所有图像转换为字节数组并将其放入“backupData”列表中。然后调用“backupOneByOne()”方法。
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?)
【讨论】:
以上是关于如何修复 Kotlin 中 FileInputStream 和 FileDescriptor 的错误路径的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Kotlin 中使用 Timestamp(Date()) 修复此错误
如何修复 io.ktor.server.engine.CommandLineKt 在 gradle/kotlin/netty 项目中抛出的“既未指定端口也未指定 sslPort”?
如何修复“AndroidRuntime: FATAL EXCEPTION: main, kotlin.KotlinNullPointerException”?尝试删除存储的数据Sqlite db时出错