Android java.io.IOException: ошибка записи: EBADF (неверный номер файла) - PullRequest
0 голосов
/ 27 ноября 2018

Я прочитал несколько сообщений об ошибке EBADF, которая не решает мою проблему.Что делает мой случай уникальным, так это то, что я пытаюсь записать в getFilesDir, который должен быть доступен для записи приложением.

Я получаю ошибку EBADF при выполнении метода шифрования.Аргумент файла создается с помощью:

new File(mContext.getFilesDir(), "file.dat")

Где находится список метода шифрования:

public static void encrypt(File file, String password, List<Object> objects) {

    byte[] salt = generateSalt();
    byte[] iv = generateIV();
    Cipher c = createCipher(password, salt, Cipher.ENCRYPT_MODE, iv);

    try (FileOutputStream fos = new FileOutputStream(file)) {
        fos.write(salt);
        fos.write(iv);
        try (CipherOutputStream cos = new CipherOutputStream(fos, c);
        ObjectOutputStream oos = new ObjectOutputStream(cos)) {
            for (Object o : objects) {
                oos.writeObject(o);
            }
        }

    } catch (FileNotFoundException e) {
        throw new RuntimeException(e);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

Кто-нибудь может понять, почему я получаю исключение?

Вот журнал исключений:

 Caused by: java.lang.RuntimeException: java.io.IOException: write failed: EBADF (Bad file number)
    at za.co.lot24media.password.util.EncryptUtil.encrypt(EncryptUtil.java:69)
    at za.co.lot24media.password.store.Store.save(Store.java:94)
    at za.co.lot24media.password.store.Store.createSamples(Store.java:179)
    at za.co.lot24media.password.store.Store.load(Store.java:76)
    at za.co.lot24media.password.activity.login.LoginAction$2.doInBackground(LoginAction.java:62)
    at za.co.lot24media.password.activity.login.LoginAction$2.doInBackground(LoginAction.java:55)
    at android.os.AsyncTask$2.call(AsyncTask.java:292)
    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
    at java.lang.Thread.run(Thread.java:818) 
 Caused by: java.io.IOException: write failed: EBADF (Bad file number)
    at libcore.io.IoBridge.write(IoBridge.java:502)
    at java.io.FileOutputStream.write(FileOutputStream.java:186)
    at java.io.OutputStream.write(OutputStream.java:82)
    at javax.crypto.CipherOutputStream.close(CipherOutputStream.java:129)
    at za.co.lot24media.password.util.EncryptUtil.encrypt(EncryptUtil.java:64)

** EDITED **

Кажется, проблема в записи ObjectOutputStream в CipherOutputStream.Когда я удаляю ObjectOutputStream из метода encrypt (), метод завершается успешно.Код ниже работает:

    public static void encrypt(File file, String password, StoreDataRecord storeDataRecord) {

    byte[] salt = generateSalt();
    byte[] iv = generateIV();
    Cipher c = createCipher(password, salt, Cipher.ENCRYPT_MODE, iv);

    try (FileOutputStream fos = new FileOutputStream(file)) {
        fos.write(salt);
        fos.write(iv);

        try (CipherOutputStream cos = new CipherOutputStream(fos, c)) {
            cos.write(new byte[10]);
        }

    } catch (FileNotFoundException e) {
        throw new RuntimeException(e);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

Я использовал байт [10] только для записи произвольных данных в поток.

** EDIT 2 **

Следующее решениетакже работает, сначала записывая данные в ByteArrayOutputStream:

public static void encrypt(File file, String password, StoreDataRecord storeDataRecord) {

    byte[] salt = generateSalt();
    byte[] iv = generateIV();
    Cipher c = createCipher(password, salt, Cipher.ENCRYPT_MODE, iv);

    try (FileOutputStream fos = new FileOutputStream(file)) {
        fos.write(salt);
        fos.write(iv);

        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
             ObjectOutputStream oos = new ObjectOutputStream(bos);
             CipherOutputStream cos = new CipherOutputStream(fos, c)) {
            oos.writeObject(storeDataRecord.getVersion());
            oos.writeObject(storeDataRecord.getItems());
            cos.write(bos.toByteArray());
        }
    } catch (FileNotFoundException e) {
        throw new RuntimeException(e);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

1 Ответ

0 голосов
/ 01 декабря 2018

Как я вижу, ваш encrypt вызов метода на doInBackground, так что это может вызвать некоторую сложную ситуацию, такую ​​как переход к другому фрагменту или создание двух экземпляров фрагмента, и это приводит к путанице в Android.Лучший способ - игнорировать метод encrypt, когда вызывается onDestroy().

И убедитесь, что ваши потоки не закрыты, прежде чем их использовать.

Надеюсь, это поможет

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...