尝试保存属性时,Androidx Exif 界面崩溃。写入失败 : EBADF (Bad file descriptor)

标签 android kotlin androidx exif android-exifinterface

当尝试使用 saveAttributes()androidx Exifinterface 保存任何 JPEG 图片时,我的程序崩溃并出现错误“write failed: EBADF (错误的文件描述符)”

我可以从新项目开始重现错误。我正在使用 Android Studio:新项目->Empty Activity。我正在使用模拟器进行测试。

下面是完整代码,其中包含我对新的空 Activity 模板所做的唯一更改。

使用androidx Exifinterface,此代码能够正确获取Exif 属性。但是,saveAttributes() 每次都会崩溃:

  • saveAttributes() 崩溃,无论我是否先 setAttribute()
  • 使用哪张图片并不重要。我试过的每张照片都会崩溃。
  • 我正在使用 JPEG 图片。我没有测试过其他 MIME 类型。
  • saveAttributes() 抛出:“无法保存新文件。原始文件存储在...”

我想设置图片的Exif属性并保存到原图文件中。正确的做法是什么?

[这篇文章应该被标记为 androidx-interface。但是那个标签不存在,而且我没有添加标签的声誉。所以我使用了标签 android-interface,它确实存在]。


build.gradle (:app)

implementation "androidx.exifinterface:exifinterface:1.3.2"

AndroidManifest.xml:

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />

MainActivity.kt:

    package com.example.test_exif_save
    
    import android.content.ContentUris
    import android.net.Uri
    import androidx.appcompat.app.AppCompatActivity
    import android.os.Bundle
    import android.provider.MediaStore
    import android.util.Log
    import androidx.core.app.ActivityCompat
    import androidx.exifinterface.media.ExifInterface
    
    class MainActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            
            // Simple method for PERMISSIONS just for quick testing
            val permissions = arrayOf(
                    android.Manifest.permission.READ_EXTERNAL_STORAGE,
                    android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    android.Manifest.permission.ACCESS_MEDIA_LOCATION,
            )
            ActivityCompat.requestPermissions(this, permissions, 0)
    
            val contentUri: Uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
    
            // id of arbitrary picture saved in Pictures/
            // The picture chosen does not matter. The same crash occurs for every picture.
            val picture_id: Long = 32
    
            val uri = ContentUris.withAppendedId(contentUri, picture_id)
            
            contentResolver.openInputStream(uri)?.use { stream ->
                val exifData = ExifInterface(stream)
    
                // Check that ExifInterface getAttribute works correctly
                val attr_model = exifData.getAttribute(ExifInterface.TAG_MODEL)
                val attr_datetime_original = exifData.getAttribute(ExifInterface.TAG_DATETIME_ORIGINAL)
                val attr_image_width = exifData.getAttribute(ExifInterface.TAG_IMAGE_WIDTH)
                Log.i("ExifData", "Model: $attr_model")
                Log.i("ExifData", "Datetime original: $attr_datetime_original")
                Log.i("ExifData", "Width: $attr_image_width")
                
                // Try to save
                // Causes fatal exception. Error: ErrnoException: write failed: EBADF (Bad file descriptor)
                exifData.saveAttributes()
            }
        }
    }

堆栈跟踪:

com.example.test_exif_save E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.test_exif_save, PID: 12188
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.test_exif_save/com.example.test_exif_save.MainActivity}: java.io.IOException: Failed to save new file. Original file is stored in /data/user/0/com.example.test_exif_save/cache/temp1652156935871844716tmp
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3449)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
        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:2066)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
     Caused by: java.io.IOException: Failed to save new file. Original file is stored in /data/user/0/com.example.test_exif_save/cache/temp1652156935871844716tmp
        at androidx.exifinterface.media.ExifInterface.saveAttributes(ExifInterface.java:4783)
        at com.example.test_exif_save.MainActivity.onCreate(MainActivity.kt:44)
        at android.app.Activity.performCreate(Activity.java:8000)
        at android.app.Activity.performCreate(Activity.java:7984)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) 
        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:2066) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:223) 
        at android.app.ActivityThread.main(ActivityThread.java:7656) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 
     Caused by: java.io.IOException: write failed: EBADF (Bad file descriptor)
        at libcore.io.IoBridge.write(IoBridge.java:540)
        at java.io.FileOutputStream.write(FileOutputStream.java:398)
        at androidx.exifinterface.media.ExifInterface.copy(ExifInterface.java:8087)
        at androidx.exifinterface.media.ExifInterface.saveAttributes(ExifInterface.java:4779)
        at com.example.test_exif_save.MainActivity.onCreate(MainActivity.kt:44) 
        at android.app.Activity.performCreate(Activity.java:8000) 
        at android.app.Activity.performCreate(Activity.java:7984) 
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309) 
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422) 
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) 
        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:2066) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:223) 
        at android.app.ActivityThread.main(ActivityThread.java:7656) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 
     Caused by: android.system.ErrnoException: write failed: EBADF (Bad file descriptor)
        at libcore.io.Linux.writeBytes(Native Method)
        at libcore.io.Linux.write(Linux.java:293)
        at libcore.io.ForwardingOs.write(ForwardingOs.java:240)
        at libcore.io.BlockGuardOs.write(BlockGuardOs.java:418)
        at libcore.io.ForwardingOs.write(ForwardingOs.java:240)
        at libcore.io.IoBridge.write(IoBridge.java:535)
        at java.io.FileOutputStream.write(FileOutputStream.java:398) 
        at androidx.exifinterface.media.ExifInterface.copy(ExifInterface.java:8087) 
        at androidx.exifinterface.media.ExifInterface.saveAttributes(ExifInterface.java:4779) 
        at com.example.test_exif_save.MainActivity.onCreate(MainActivity.kt:44) 
        at android.app.Activity.performCreate(Activity.java:8000) 
        at android.app.Activity.performCreate(Activity.java:7984) 
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309) 
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422) 
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) 
        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:2066) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:223) 
        at android.app.ActivityThread.main(ActivityThread.java:7656) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 

最佳答案

我遇到了同样的问题。 通过从 FileDescriptor 而不是 InputStream 创建 ExifInterface 来修复它。 替换

val exifData = ExifInterface(stream)

val exifData = ExifInterface(context.contentResolver.openFileDescriptor(new, "rw", null)!!.fileDescriptor)

(根据您的喜好处理 FileDescriptor 可空性)。

关于尝试保存属性时,Androidx Exif 界面崩溃。写入失败 : EBADF (Bad file descriptor),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66107689/

相关文章:

java - 错误: [Dagger/MissingBinding] error message doesn't make sense

Android Dark 主题反转矢量绘图的颜色

java - 每个请求在 VertX 中设置单独的超时

Visual Studio NuGet 中适用于 Xamarin.Android 的 Androidx 库

gradle - 迁移到 AndroidX 后出现错误 : cannot find symbol import com. google.firebase.iid.InstanceIdResult

Android在gradle中添加库

android - AutoCompleteTextView 为下拉列表创建边距

android:点击打开和隐藏数据

java - 柱体改造2包括大括号

android - 如果显示软键盘,则“完整版面”将向上移动