Android:IOException read fail:EBADF (Bad file descriptor)

碰到此问题请先看:Android Q:文件上传(之前的文章有点问题)因为此问题的根本原因我没分析出来,怀疑也是文件过大然后直接读取的时候失败了,无效的话,再看此篇吧。

 

写这篇博客主要想记录一下这个问题,我觉得大家应该都不会碰到。

在我之前的一篇文章Android Q:上传图片java.io.FileNotFoundException: open failed: EACCES (Permission denied) 中有说到,新安卓版本下,使用公共文件资源不能够File file = new File(path)了,需要使用FD,也就是FileDescriptor。现在,我这边碰到了一个非常非常奇葩的问题,就如标题所示:

IOException read fail:EBADF (Bad file descriptor)

这个错误,是try-catch出来,然后Toast到屏幕上,截图下来的。是不是这套操作,很奇怪,为什么我不debug?

这个错误,在debug环境下的安装包,是不会报错的,在release安装包下,会报错。在测试机上会报错,在我手机findx上不报错。在上一个项目中用到,没报过这个错误,在这个项目后期,碰到了这个错误。

非常奇葩,根本想不通,为什么同一套代码,连接口地址都一样,release包就报错了。

我把功能代码整合了一下,放上来

//现在假定,已经获取到了一个资源的Uri 并且要上传

private void update() throws IOException {
    ParcelFileDescriptor parcelFileDescriptor = getApplication.getContentResolver().openFileDescriptor(uri, "r");
        
    FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
    FileInputStream fis = new FileInputStream(fileDescriptor);
    ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
    byte[] buff = new byte[1024*4]; //buff用于存放循环读取的临时数据
    int rc = 0;
    while ((rc = fis.read(buff, 0, 100)) > 0) {
       swapStream.write(buff, 0, rc);
    }
    MultipartBody.Builder builder = new MultipartBody.Builder()
                .setType(MultipartBody.FORM);//表单类型
        RequestBody body = RequestBody.create(MediaType.parse("multipart/form-data"), swapStream.toByteArray());//表单类型

        builder.addFormDataPart("file", "xxx.mp4", body);
    Retrofit.getApi.update(builder.build().parts())
            .compose(做一些切换线程的操作,和数据处理)
            .subscribe(new Observe{
            //成功 失败回调
    });
}

我那边分好几个文件调用,但是整套流程大致就是这样,获取文件byte[],构建formData文件Retrofit上传,调用接口。

调用的时候,你就需要try-catch,然后release环境下,我这边就报错了。

直接说解决办法吧,因为我也不知道为什么会报错,有知道的大佬可以提点一下我,由于我用的MVVM框架,而ViewModel中是不能持有activity的context的,但是可以有application,因此在使用getContentResolver(),我用的是application。当时我是把这代码放在了MainActivity中测试,发现居然不报错,成功上传了,对比下,只有在获取getContentResolver()这个时候不一样。

我把所有getContentResolver的地方都使用了activity的context,就没有报这个错误了。就是代码结构变化比较大,需要把获取ParcelFileDescriptor放在View模块执行,然后再到ViewModel中转化成byte[]。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
这个警告信息提示了在执行read(buffer)时,底层操作系统发生了EBADF错误,这通常是由于文件描述符已经关闭或者无效导致的。因此,解决方法如下: 1. 确认InputStream对象是否已正确打开,如果未正确打开则会出现上述错误。可以通过检查InputStream对象是否为null或调用available()方法检查可读字节数是否大于0来确定InputStream对象是否已正确打开。 2. 确认读取文件文件描述符是否已正确关闭,如果已关闭则无法进行读取操作。可以通过调用FileInputStream对象的close()方法来关闭文件描述符。 3. 可能是由于多个线程同时对同一个文件进行读取操作导致的问题,可以通过使用同步锁或者将读取操作放在单独的线程中来避免此问题。 以下是一个使用同步锁避免多线程读取同一个文件时出现上述问题的示例代码: ```java public static synchronized byte[] inputStreamToByteArray(InputStream inputStream) throws IOException { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { byteArrayOutputStream.write(buffer, 0, bytesRead); } return byteArrayOutputStream.toByteArray(); } ``` 使用时只需要将读取操作放在一个同步方法中即可: ```java InputStream inputStream = new FileInputStream("file.txt"); byte[] bytes = inputStreamToByteArray(inputStream); ``` 如果以上方法无法解决问题,可以尝试重新打开文件或者重新创建InputStream对象,并且检查文件访问权限是否正确。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值