Java输出流输出数据错误原因分析

自己正在模仿SpringMVC封装Servlet, 在处理文件上传时, 之前一直都用的是开源框架实现, 于是很好奇他们是怎么实现的, 就网上查资料动手实现一下.

结果万万没想到上传的文件中间多出了一段奇怪的数据

过程如下:

1. 前端发送表单数据, 一张图片和几个name-value, F12可以看到数据发送的格式

------WebKitFormBoundary 加上一些随机字符作为分隔标志, 两个分隔之间是具体的数据, 图片二进制数据就没有显示出来

 

2. 后端直接request.getInputStream把数据读出来再写到文件里, 大概的代码如下:

DataInputStream formDataReader = new DataInputStream(request.getInputStream());
String savePath = request.getServletContext().getRealPath("/files/");
new File(savePath).mkdirs();
String fileName = String.valueOf(System.currentTimeMillis() + (int)(Math.random() * 100000));
File outputFile = new File(savePath + fileName);
boolean createResult = outputFile.createNewFile();
if(!createResult){
    throw new Exception("无法上传文件");
}
DataOutputStream formDataWriter = new DataOutputStream(new FileOutputStream(outputFile));
byte[] chunk = new byte[1024];
while(formDataReader.read(chunk) != -1){
    formDataWriter.write(chunk);
}
formDataWriter.flush();
formDataWriter.close();

这个时候用01Editor打开文件, 对比原来的图片, 发现头尾多了------WebKitFormBoundaryN1Nz7fpJA9ObLth4之类的表单信息, 去除即可, 之后改成图片后缀打开, 发现图片的内容显示不完整

用Beyond Compare比较后发现, 文件比原文件在中间部分多出了一部分奇怪的数据

于是乎百思不得其解

对比其他人的代码中发现问题所在

将代码

byte[] chunk = new byte[1024];
while(formDataReader.read(chunk) != -1){
    formDataWriter.write(chunk);
}


改成

byte[] chunk = new byte[1024];
int len = -1;
while((len = formDataReader.read(chunk)) != -1){
    formDataWriter.write(chunk, 0, len);
}
formDataWriter.flush();
formDataWriter.close();

之后上传图片, 将头尾的表单数据删去, 图片与原图一模一样

 

由此可见, InputStream读取数据还未读到结尾前, 每次并非读取完整的byte[] 数组, 因此写数据时, 最好用

OutputStream.write(byte[] data, 0, length); 

而非

OutputStream.write(byte[] data);

否则可能上次读取1024个byte的数据, 这次读取512个byte, 结果把这次的512个byte和上次存数组后面的512个byte一起写出去, 就会导致出错.

这个问题困扰了我一天, 换了很多张图片都有这种情况, 且恰巧是中间一小段数据异常

看来等有空得好好看下Java源码好好研究下  😋

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值