我已经阅读了几篇关于EBADF错误的文章,但没有解决我的问题。我的情况独特之处在于,我正在尝试写入getFilesDir,这应该是应用程序可写的。
当执行encrypt方法时,我遇到了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
即可。 - user207421ObjectOutputStream
,当块退出时将被关闭,这将关闭底层流和文件,这将关闭FileOutputStream
,当需要刷新CipherOutputStream
时,它将在关闭时引发此异常,显然它确实需要刷新。在(冗余的)循环之后添加oos.flush()
以确保在关闭时CipherOutputStream
不需要刷新。 - user207421errno
为EBADF
,只有一个原因:"EBADF
fildes
参数未打开写入的有效文件描述符。使用 Java 很难获得完全无效的文件描述符 - 甚至不表示已打开的文件的值。因此,您可能没有文件的写入权限。它已经存在了吗? - Andrew Henle