Kotlin中使用URLConnection下载文件时文件大小异常(16MB图片仅保存84B)的原因排查
问题分析与修复方案
嘿,我看了你的代码,这84B的文件大概率是两个核心原因导致的:要么你下载的根本不是图片数据,要么是写入文件的逻辑被意外跳过了,咱们一步步来捋清楚:
1. 最致命的坑:写入逻辑被Content-Disposition判断挡住了
你代码里读取输入流并写入文件的核心逻辑,完全包裹在if (disposition != null)的代码块中:
if (disposition != null) { // 解析文件名的逻辑 // ... // 读取流、写文件的核心代码全在这里! `is` = conn.inputStream os = FileOutputStream(File(outputDir, fileName)) // ...写文件的循环 }
如果你的服务器没有返回Content-Disposition这个响应头,那这段写文件的代码根本不会执行!但你可能还是创建了空文件,或者不小心写入了少量日志内容,这就解释了为什么文件只有84B。
修复方法:把写文件的逻辑抽出来,不管有没有Content-Disposition都执行,同时给文件名设置一个默认值:
// 先处理文件名,没有disposition就用默认名兜底 var fileName = "user_sign.jpg" if (disposition != null) { val target = "filename=" val index = disposition.indexOf(target) if (index != -1) { fileName = disposition.substring(index + target.length).replace("\"", "") } println("Content-Type = $contentType") println("Content-Disposition = $disposition") println("fileName = $fileName") } // 把写文件的逻辑移到外面,确保一定会执行 `is` = conn.inputStream os = FileOutputStream(File(outputDir, fileName)) val BUFFER_SIZE = 4096 var bytesRead: Int val buffer = ByteArray(BUFFER_SIZE) while (`is`.read(buffer).also { bytesRead = it } != -1) { os.write(buffer, 0, bytesRead) } // 别忘了关闭流(或者用Kotlin的use函数自动关闭更安全) os.close() `is`.close()
2. 请求头设置错误:你告诉服务器只接受JSON,但要下载的是图片
你设置了Accept: application/json:
conn.setRequestProperty("Accept", "application/json")
这相当于明确告诉服务器:"我只想要JSON格式的数据",服务器可能直接返回了一段JSON错误信息(比如"请求格式不匹配"),而不是图片——这84B很可能就是这段JSON的大小!
修复方法:把Accept头改成接受图片类型,或者用通用类型兼容所有情况:
// 只接受图片类型,更精准 conn.setRequestProperty("Accept", "image/*") // 或者用通用类型,接受所有响应格式 // conn.setRequestProperty("Accept", "*/*")
3. 几个额外的优化建议
- 你的连接超时只有1.5秒,对于16MB的图片来说大概率会超时,建议延长超时时间:
conn.connectTimeout = 10000 // 10秒连接超时 conn.readTimeout = 10000 // 加上读取超时,防止读取数据时卡住 - 用Kotlin的
use函数自动管理流资源,避免手动关闭时的异常泄漏:conn.inputStream.use { inputStream -> FileOutputStream(File(outputDir, fileName)).use { outputStream -> val buffer = ByteArray(4096) var bytesRead: Int while (inputStream.read(buffer).also { bytesRead = it } != -1) { outputStream.write(buffer, 0, bytesRead) } } } - 可以先把输入流转成字符串打印出来,看看那84B到底是什么内容——如果是JSON,直接就能知道服务器为啥没返回图片了。
内容的提问来源于stack exchange,提问作者jyk
相关产品推荐
相关产品推荐

