Android BufferedInputStream.read 导致的问题...没解决...

问题描述

Android中使用BufferedInputStream.read()读取大文件(约2.93G)时, 偶尔出现异常。

异常代码(文件上传)

//1.通过Uri获取文件的InputStream
val ins: InputStream = AppUtils.getContext().contentResolver.openInputStream(uri)
//2.每次读取8192个字节,速度
val buffered: BufferedInputStream = ins.buffered(8192)
//3.临时存储缓冲输出的字节流
val out = ByteArrayOutputStream()
//4.用来存储每次读取到的字节数组
val bytes = ByteArray(BUFFER_SIZE)
//5.每写入 4M 数据,开始上传
val onePartSize = 4 * 1024 * 1024
while (buffered.read(bytes) != -1) { //⭐ 此处报错 ENOTCONN
    out.write(bytes)
     //相等时开始上传, eg: 上传 Buffer out.size()=3145728 partSize=3145728 pCount=1
    if (out.size() >= onePartSize) {
        if (!isNetOk()) {
            out.reset()
            //buffered.reset() //会报错
            out.close()
            buffered.close()
            return
        }
        ...
        uploadPart(..., out.toByteArray()) //上传分片数据
        out.reset()
}

if (out.size() > 0) {
    //上传不足 onePartSize (4M) 的数据
    uploadPart(...)
    out.reset()
}
...

错误详情

  • java.io.IOException: read failed: ENOTCONN (Transport endpoint is not connected)
  • android.system.ErrnoException: read failed: ENOTCONN (Transport endpoint is not connected)
W/System.err: java.io.IOException: read failed: ENOTCONN (Transport endpoint is not connected)
W/System.err:     at libcore.io.IoBridge.read(IoBridge.java:523)
W/System.err:     at java.io.FileInputStream.read(FileInputStream.java:313)
W/System.err:     at android.os.ParcelFileDescriptor$AutoCloseInputStream.read(ParcelFileDescriptor.java:975)
W/System.err:     at java.io.BufferedInputStream.read1(BufferedInputStream.java:286)
W/System.err:     at java.io.BufferedInputStream.read(BufferedInputStream.java:347)
W/System.err:     at java.io.FilterInputStream.read(FilterInputStream.java:107)
W/System.err:     at cn.zqrb.gallery.http.XHttp$handleUploadFiles$$inlined$forEachIndexed$lambda$1.apply(XHttp.kt:790)
W/System.err:     at cn.zqrb.gallery.http.XHttp$handleUploadFiles$$inlined$forEachIndexed$lambda$1.apply(XHttp.kt:42)
W/System.err:     at io.reactivex.internal.operators.flowable.FlowableMap$MapSubscriber.onNext(FlowableMap.java:63)
W/System.err:     at io.reactivex.internal.subscriptions.ScalarSubscription.request(ScalarSubscription.java:55)
W/System.err:     at io.reactivex.internal.subscribers.BasicFuseableSubscriber.request(BasicFuseableSubscriber.java:153)
W/System.err:     at io.reactivex.internal.operators.flowable.FlowableSubscribeOn$SubscribeOnSubscriber.requestUpstream(FlowableSubscribeOn.java:133)
W/System.err:     at io.reactivex.internal.operators.flowable.FlowableSubscribeOn$SubscribeOnSubscriber.onSubscribe(FlowableSubscribeOn.java:90)
W/System.err:     at io.reactivex.internal.subscribers.BasicFuseableSubscriber.onSubscribe(BasicFuseableSubscriber.java:67)
W/System.err:     at io.reactivex.internal.operators.flowable.FlowableJust.subscribeActual(FlowableJust.java:34)
W/System.err:     at io.reactivex.Flowable.subscribe(Flowable.java:14935)
W/System.err:     at io.reactivex.internal.operators.flowable.FlowableMap.subscribeActual(FlowableMap.java:37)
W/System.err:     at io.reactivex.Flowable.subscribe(Flowable.java:14935)
W/System.err:     at io.reactivex.Flowable.subscribe(Flowable.java:14882)
W/System.err:     at io.reactivex.internal.operators.flowable.FlowableSubscribeOn$SubscribeOnSubscriber.run(FlowableSubscribeOn.java:82)
W/System.err:     at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
W/System.err:     at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:266)
W/System.err:     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
W/System.err:     at java.lang.Thread.run(Thread.java:929)
W/System.err: Caused by: android.system.ErrnoException: read failed: ENOTCONN (Transport endpoint is not connected)
W/System.err:     at libcore.io.Linux.readBytes(Native Method)
W/System.err:     at libcore.io.Linux.read(Linux.java:190)
W/System.err:     at libcore.io.ForwardingOs.read(ForwardingOs.java:177)
W/System.err:     at libcore.io.BlockGuardOs.read(BlockGuardOs.java:303)
W/System.err:     at libcore.io.ForwardingOs.read(ForwardingOs.java:177)
W/System.err:     at libcore.io.IoBridge.read(IoBridge.java:513)
W/System.err: 	... 26 more


2021年8月12日 16:36:39

测试Demo

很遗憾没能复现问题..., 可能测试的太少

GitHub 👉 https://github.com/javakam/FileOperator/blob/master/app/src/main/java/com/ando/file/sample/harmony/FileHarmonyActivity.kt

FileHarmonyActivity.kt

/**
 * 模拟文件上传 (Simulate file upload)
 */
fun uploadFile(context: Context, uri: Uri, fileTotalSize: Long, callBack: (String?) -> Unit) {
    //1.通过Uri获取文件的InputStream
    val ins: InputStream = context.contentResolver.openInputStream(uri) ?: return
    //2.每次读取8192个字节,速度
    val buffered: BufferedInputStream = ins.buffered(8192)
    //3.临时存储缓冲输出的字节流
    val out = ByteArrayOutputStream()
    //4.用来存储每次读取到的字节数组
    val bytes = ByteArray(1024 * 1024)
    //5.每写入 5M 数据, 开始上传
    val onePartSize = 5 * 1024 * 1024
    //6.计算分片数量
    var totalCount: Int = ceil(fileTotalSize * 1.00 / onePartSize).toInt()
    //不足 onePartSize (5M) 直接传过去
    totalCount = if (totalCount < 1) 1 else totalCount
    callBack.invoke("🌴开始上传, 总共${totalCount}片")
    var partCount = 0
    while (buffered.read(bytes) != -1) { //************ 此处报错 ENOTCONN ************
        out.write(bytes)
        //相等时开始上传, eg: 上传 Buffer out.size()=3145728 partSize=3145728 pCount=1
        if (out.size() >= onePartSize) {
            Thread.sleep(30)
            //上传分片数据
            val log = "第${partCount}片  大小: ${(out.toByteArray()).size / (1024 * 1024)}M"
            callBack.invoke(log)
            Log.e("123", log)
            partCount += 1
            out.reset()
        }
    }
    if (out.size() > 0) {
        //上传不足 onePartSize (5M) 的数据
        val log = "最后一片($partCount)  大小: ${(out.toByteArray()).size / 1024}KB"
        callBack.invoke(log)
        Log.e("123", log)
        out.reset()
    }
    callBack.invoke("🌴上传完成")
    callBack.invoke(null)
}
posted @ 2021-07-12 16:44  javakam  阅读(0)  评论(0)    收藏  举报  来源