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
/**
* 模拟文件上传 (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)
}

浙公网安备 33010602011771号