Android java.io.IOException: write failed: EBADF (Bad file number)

Posted

技术标签:

【中文标题】Android java.io.IOException: write failed: EBADF (Bad file number)【英文标题】: 【发布时间】:2019-04-28 23:41:20 【问题描述】:

我已经阅读了几篇关于 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)

** 已编辑 **

问题似乎在于 ObjectOutputStream 写入 CipherOutputStream。当我从 encrypt() 方法中删除 ObjectOutputStream 时,该方法成功。下面的代码有效:

    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);
    

我使用 byte[10] 只是将任意数据写入流。

** 编辑 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);
    

【问题讨论】:

发布异常日志 您不需要遍历对象。写List How to know whether writing to stream would result in java.io.IOException: write failed: EBADF (Bad file number)的可能重复 它不是完全重复的,而是可能最有帮助的(许多)重复。 最里面的try-with-resources是ObjectOutputStream,在block退出的时候会关闭,会关闭底层的流和文件,会关闭FileOutputStream,这会导致当CipherOutputStream 需要刷新时关闭此异常,它显然是这样做的。在(冗余)循环之后添加oos.flush(),以确保CipherOutputStream 在关闭时不需要刷新。 【参考方案1】:

我在doInBackground 上看到您的encrypt 方法调用,因此它可能会产生一些复杂的情况,例如移动到另一个片段或创建两个片段实例,这会使android 感到困惑。最好的方法是在调用 onDestroy() 时忽略 encrypt 方法。

并确保您的流在使用前没有关闭。

希望对你有帮助

【讨论】:

以上是关于Android java.io.IOException: write failed: EBADF (Bad file number)的主要内容,如果未能解决你的问题,请参考以下文章

eclipse中启动Genymotion模拟器的错误

Gradle Plugin v0.13.1 后重复的 Zip 条目

Android逆向系列文章— Android基础逆向

Android 逆向Android 权限 ( Android 逆向中使用的 android.permission 权限 | Android 系统中的 Linux 用户权限 )

Android 逆向Android 权限 ( Android 逆向中使用的 android.permission 权限 | Android 系统中的 Linux 用户权限 )

android 21 是啥版本