Androidx Exifinterface аварийно завершает работу при попытке сохранить атрибуты. Ошибка записи: EBADF (неверный дескриптор файла)

При попытке сохранить любое изображение JPEG с помощью androidx моя программа вылетает с ошибкой «ошибка записи: EBADF (плохой дескриптор файла)»

Я могу воспроизвести ошибку, начиная с нового проекта. Я использую Android Studio: new project-> Empty Activity. Использую для тестирования эмулятор.

Ниже приведен полный код с единственными изменениями, которые я внес в новый шаблон Empty Activity.

Использование androidx Exifinterface, этот код может правильно получать атрибуты Exif. Однако вылетает каждый раз:

  • вылетает независимо от того, если я сначала setAttribute() или нет.
  • Какая картинка используется, не имеет значения. Вылетает для каждой картинки, которую я пробовал.
  • Я использую изображения в формате JPEG. Я не тестировал другие типы пантомимы.
  • saveAttributes() выдает: «Не удалось сохранить новый файл. Исходный файл хранится в ...»

Я хочу установить атрибуты Exif изображения и сохранить их в исходный файл изображения. Как правильно?

[Это сообщение должно быть помечено androidx-interface. Но этого тега не существует, и у меня нет репутации, чтобы добавить тег. Итак, я использовал тег android-interface, который существует].


build.gradle (: приложение)

      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) 

2 ответа

У меня такая же проблема. Исправлено путем создания ExifInterface из FileDescriptor вместо InputStream. Заменять

      val exifData = ExifInterface(stream)

С

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

(Обработка обнуляемости FileDescriptor на ваш вкус).

Я никогда не кодирую для Android, но просто быстро взглянув на код, похоже, что вы передаете входной поток в интерфейс exif. Вам нужно настроить отдельный выходной поток для записи контента? имеет смысл, почему вы можете читать, но тогда при записи возникает ошибка плохого дескриптора файла.

не могли бы вы попробовать запустить exifinterface для статического файла, а не для потока? посмотрим, изменится ли это что-нибудь.

Другие вопросы по тегам