读取POST请求体时文件上传损坏问题排查
问题分析与解决方案
你的代码导致文件损坏的核心原因是错误地使用字符流处理二进制文件数据:
BufferedReader和OutputStreamWriter是字符流,会将字节按默认编码(通常是UTF-8)转换为字符,再转回字节写入文件。这个转换过程会破坏二进制文件(如图片、压缩包)的原始字节结构,导致文件损坏。- 另外,字符层面的边界匹配逻辑也存在风险,可能因编码问题导致边界识别错误,进而写入多余或缺失的字节。
修正方案
1. 改用字节流处理数据
直接使用字节流(InputStream、FileOutputStream)操作,跳过字符编码转换,确保原始字节完整保留。
2. 基于字节数组实现边界匹配
用字节数组存储边界字符串,逐字节比对,避免字符编码干扰。
修正后的代码
// 处理POST请求 File file_upload = new File(Environment.getExternalStorageDirectory(), "Download/" + filename); if (file_upload.createNewFile()) { // 使用try-with-resources自动关闭流,避免资源泄漏 try (FileOutputStream out = new FileOutputStream(file_upload)) { // 将边界转换为ASCII字节数组(HTTP协议边界采用ASCII编码) byte[] boundaryBytes = ("\r\n--" + boundary).getBytes(StandardCharsets.US_ASCII); int boundaryLength = boundaryBytes.length; // 临时存储正在匹配的边界字节 byte[] matchBuffer = new byte[boundaryLength]; int matchIndex = 0; int readByte; // 使用Socket原始的InputStream,不要用BufferedReader包装 InputStream in = socket.getInputStream(); while ((readByte = in.read()) != -1) { byte currentByte = (byte) readByte; // 检查当前字节是否匹配边界的对应位置 if (currentByte == boundaryBytes[matchIndex]) { matchBuffer[matchIndex] = currentByte; matchIndex++; // 完全匹配边界,终止文件写入 if (matchIndex == boundaryLength) { break; } } else { // 如果之前有部分匹配的字节,先写入文件 if (matchIndex > 0) { out.write(matchBuffer, 0, matchIndex); matchIndex = 0; } // 写入当前字节 out.write(currentByte); } } } catch (IOException e) { e.printStackTrace(); } }
额外注意事项
- 必须直接使用Socket的
InputStream,禁止用BufferedReader或其他字符流包装,否则仍会破坏二进制数据。 - 边界字符串的字节转换必须用
US_ASCII编码,确保与HTTP协议的边界定义一致,避免因编码差异导致匹配失败。 - 处理大文件时,可以考虑使用缓冲区(如
byte[] buffer = new byte[4096])批量读取写入,提升性能。
内容的提问来源于stack exchange,提问作者Ammar
相关产品推荐
相关产品推荐

