bug修改之后的代码:
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.lubansoft.test.upload.po.UploadRecord;
import com.lubansoft.test.upload.po.UploadResult;
public class FileUpload {
/**
* 接收上传的参数和文件
*/
public UploadResult upload(HttpServletRequest request,HttpServletResponse response){
UploadResult uploadResult = new UploadResult();
try {
InputStream in = new BufferedInputStream(request.getInputStream(),10240);
String requestHeader = readLine(in);
String line = null;
Map<String,String> param = new HashMap<String, String>();
Map<String,String> fileUploadResults = new HashMap<String, String>();
uploadResult.setParams(param);
uploadResult.setFileUploadResults(fileUploadResults);
/**
* 判断是否是文件/参数
*/
if("------parameters------".equals(requestHeader)){
/**
* 上传参数的格式:
* 第一行: ------parameters------
* 第二行:"parameterLength=" + parameterLength
* 第三行: key1=value1&key2=value2........
*/
line = readLine(in);
int length = 0;
if(line != null){
if("parameterLength".equals(line.split("=")[0])){
length = Integer.parseInt(line.split("=")[1]);
}
}
byte[] b = null;
if(length != 0){
b = new byte[length];
in.read(b, 0, length);
line = new String(b,0,length,"utf-8");
}
if(line != null){
String[] params = line.split("&");
if(params!=null && params.length>0){
for(String keyValue : params){
param.put(keyValue.split("=")[0], keyValue.split("=")[1]);
}
}
}
System.out.println(param);
/**
*读取最后的一个换行符:\n
*/
readLine(in);
if("------file begin------".equals(line=readLine(in))){
startTimerAndUploadFile(request, in, fileUploadResults);
}
}else if("------file begin------".equals(requestHeader)){
startTimerAndUploadFile(request, in, fileUploadResults);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.getWriter().write("upload complete !");
} catch (IOException e) {
e.printStackTrace();
}
}
return uploadResult;
}
/**
* 启动定时器,开始上传文件
*/
public void startTimerAndUploadFile(HttpServletRequest request,InputStream in,Map<String,String> fileUploadResults){
Timer timer = new Timer();
UploadRateTimerTask task = new UploadRateTimerTask(request);
long interval = FileUploadUtil.getTimerInfo(request) != null ? Long.parseLong(FileUploadUtil.getTimerInfo(request)[0]) : 1000;
timer.schedule(task, 0 , interval);
saveFile(in, request, task,fileUploadResults);
timer.cancel();
}
//保存文件
public void saveFile(InputStream in ,HttpServletRequest request,UploadRateTimerTask task,Map<String,String> fileUploadResults){
String line=null;
RandomAccessFile raf = null;
UploadRecord uploadRecord = null;
String fileMD5_client = null;
String fileMD5_server = null;
int blockSize = FileUploadUtil.getBlockSize();
try {
task.setTotal_uploadSize(0);
//先读到该文件的信息头“fileName=ddd&fileSize=xxx&uploadSize=aaa”
line = readLine(in);
if(line != null){
uploadRecord = FileUploadUtil.getUploadRecoreFromString(line);
fileMD5_client = uploadRecord.getFileMD5();
HttpSession session = request.getSession();
String folder = session.getServletContext().getRealPath(UploadConfigConstants.UPLOAD_FILE);
String filepath = folder+File.separator + FileUploadUtil.getFileNameByUploadRecord(uploadRecord);
File file = new File(filepath);
if(! file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
if(! file.exists()){
file.createNewFile();
}
/**
* 先将properties文件放到临时文件夹下(tmep)
*/
String config_path = session.getServletContext().getRealPath(UploadConfigConstants.BREAK_POINT) + File.separator +
"temp/" + FileUploadUtil.getConfigFileNameByUploadRecord(uploadRecord);
File config_file = new File(config_path);
if(! config_file.getParentFile().exists()){
config_file.getParentFile().mkdirs();
}
if (! config_file.exists()) {
config_file.createNewFile();
}
raf = new RandomAccessFile(file, "rwd");
raf.setLength(uploadRecord.getFileSize());
//将读取文件的指针移动到断点位置
raf.seek(uploadRecord.getUploadSize());
//计算出从断点位置到文件结尾,还剩下的文件大小
long leftSize = uploadRecord.getFileSize()-uploadRecord.getUploadSize();
//本次上传,上传完成的文件大小
long completeSize = 0l;
/**
* 接下来是文件的内容
*/
int n=-1;
byte[] b = new byte[2048];
int addSize = 0;
/**
* 在上传文件的时候,再去判断一下是否已经有程序在上传该文件
* 作为确认,防止万一
*/
boolean isStarted = false;
if(FileUploadUtil.isUploadStarted(request, uploadRecord)){
isStarted = true;
}
/**
* 为定时器动态绑定uploadRecord对象
*/
task.setUploadRecord(uploadRecord);
/**
* 判断文件从断点开始,还有多大文件需要传输,如果太小(小于 1 k )就要特殊处理
* 因为这时候不能使用 in.read(b) ,而只能使用 in.read(b,0,leftSize)
*/
if((completeSize + b.length) <= leftSize){
while((n=in.read(b)) != -1){
if(! isStarted){
raf.write(b,0,n);
completeSize += n;
addSize += n;
task.setTotal_uploadSize(completeSize);
if(addSize >= blockSize){
FileUploadUtil.updateUploadSize(request, uploadRecord, addSize);
addSize = 0;
}
}
/**
* 最后一部分特殊处理
*/
if((completeSize + b.length) >= leftSize){
int num = -1;
while(true){
/**
* num表示最后一部分还剩下多少,也就是应该读取的大小
* n表示真正读取到的部分是多少,也就是实际上读取到的大小
* n和num可能并不相同,一直到leftSize == completeSize才说明最后一部分处理完成
*/
num = (int)(leftSize-completeSize);
n = in.read(b, 0, num);
completeSize += n;
if(! isStarted){
raf.write(b,0,n);
addSize += n;
task.setTotal_uploadSize(completeSize);
if(addSize >= blockSize){
FileUploadUtil.updateUploadSize(request, uploadRecord, addSize);
addSize = 0;
}
}
/**
* 如果leftSize == completeSize说明最后一部分处理完成
*/
if(leftSize == completeSize){
raf.close();
FileUploadUtil.updateUploadSize(request, uploadRecord, addSize);
addSize = 0;
//完成一个文件的上传,将该文件的完成百分比改为100%
task.setTaskComplete();
//完成一个文件的上传,将该文件的isStopped改为stopped
FileUploadUtil.setConfigFileStoped(request, uploadRecord);
fileMD5_server = MD5Util.getFileMD5String(file);
if(fileMD5_server != null && fileMD5_client != null){
if(fileMD5_server.equals(fileMD5_client)){
fileUploadResults.put(file.getName(), "OK");
/**
* 文件上传完成并且校验成功,则将其配置文件转移到已上传成功的文件夹
*/
FileUploadUtil.MoveFile(config_file, session.getServletContext().getRealPath(UploadConfigConstants.BREAK_POINT));
}
}else{
/**
* 文件上传完成,但是文件已损坏
*/
fileUploadResults.put(file.getName(), "DAMAGED");
}
readLine(in);
line = readLine(in);
if("------file begin------".equals(line)){
saveFile(in, request,task,fileUploadResults);
}
break;
}
}
}
}
}else{//判断文件从断点开始,如果剩余文件太小(小于 1 k )就要特殊处理
int num = -1;
while(true){
num = (int)(leftSize-completeSize);
n = in.read(b, 0, num);
completeSize += n;
if(! isStarted){
raf.write(b,0,n);
addSize += n;
task.setTotal_uploadSize(completeSize);
if(addSize >= blockSize){
FileUploadUtil.updateUploadSize(request, uploadRecord, addSize);
addSize = 0;
}
}
if(leftSize == completeSize){
raf.close();
FileUploadUtil.updateUploadSize(request, uploadRecord, addSize);
addSize = 0;
//完成一个文件的上传,将该文件的完成百分比改为100%
task.setTaskComplete();
//完成一个文件的上传,将该文件的isStopped改为stopped
FileUploadUtil.setConfigFileStoped(request, uploadRecord);
fileMD5_server = MD5Util.getFileMD5String(file);
if(fileMD5_server != null && fileMD5_client != null){
if(fileMD5_server.equals(fileMD5_client)){
fileUploadResults.put(file.getName(), "OK");
/**
* 文件上传完成并且校验成功,则将其配置文件转移到已上传成功的文件夹
*/
FileUploadUtil.MoveFile(config_file, session.getServletContext().getRealPath(UploadConfigConstants.BREAK_POINT));
}
}else{
/**
* 文件上传完成,但是文件已损坏
*/
fileUploadResults.put(file.getName(), "DAMAGED");
}
readLine(in);
line = readLine(in);
if("------file begin------".equals(line)){
saveFile(in, request,task,fileUploadResults);
}
break;
}
}
}
/**
* 文件上传完成,将状态修改为 “stoped”
*/
if(uploadRecord != null){
FileUploadUtil.setConfigFileStoped(request, uploadRecord);
}
}
// }
} catch (IOException e) {
/**
* 上传过程中出现异常,将状态修改为 “stoped”
*/
e.printStackTrace();
}finally{
/**
* 上传过程中出现异常,将状态修改为 “stoped”
*/
if(uploadRecord != null){
FileUploadUtil.setConfigFileStoped(request, uploadRecord);
}
if(raf != null){
try {
raf.close();
} catch (IOException e1) {
e1.printStackTrace();
}
raf = null;
}
}
}
/**
* 读取一行内容
*/
private String readLine(InputStream in) {
return FileUploadUtil.readLine(in);
}
}
之前的代码:
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.lubansoft.test.upload.po.UploadRecord;
import com.lubansoft.test.upload.po.UploadResult;
public class FileUpload {
/**
* 接收上传的参数和文件
*/
public UploadResult upload(HttpServletRequest request,HttpServletResponse response){
UploadResult uploadResult = new UploadResult();
try {
InputStream in = new BufferedInputStream(request.getInputStream(),10240);
String requestHeader = readLine(in);
String line = null;
Map<String,String> param = new HashMap<String, String>();
Map<String,String> fileUploadResults = new HashMap<String, String>();
uploadResult.setParams(param);
uploadResult.setFileUploadResults(fileUploadResults);
/**
* 判断是否是文件/参数
*/
if("------parameters------".equals(requestHeader)){
/**
* 上传参数的格式:
* 第一行: ------parameters------
* 第二行:"parameterLength=" + parameterLength
* 第三行: key1=value1&key2=value2........
*/
line = readLine(in);
int length = 0;
if(line != null){
if("parameterLength".equals(line.split("=")[0])){
length = Integer.parseInt(line.split("=")[1]);
}
}
byte[] b = null;
if(length != 0){
b = new byte[length];
in.read(b, 0, length);
line = new String(b,0,length,"utf-8");
}
if(line != null){
String[] params = line.split("&");
if(params!=null && params.length>0){
for(String keyValue : params){
param.put(keyValue.split("=")[0], keyValue.split("=")[1]);
}
}
}
System.out.println(param);
/**
*读取最后的一个换行符:\n
*/
readLine(in);
if("------file begin------".equals(line=readLine(in))){
startTimerAndUploadFile(request, in, fileUploadResults);
}
}else if("------file begin------".equals(requestHeader)){
startTimerAndUploadFile(request, in, fileUploadResults);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.getWriter().write("upload complete !");
} catch (IOException e) {
e.printStackTrace();
}
}
return uploadResult;
}
/**
* 启动定时器,开始上传文件
*/
public void startTimerAndUploadFile(HttpServletRequest request,InputStream in,Map<String,String> fileUploadResults){
Timer timer = new Timer();
UploadRateTimerTask task = new UploadRateTimerTask(request);
long interval = FileUploadUtil.getTimerInfo(request) != null ? Long.parseLong(FileUploadUtil.getTimerInfo(request)[0]) : 1000;
timer.schedule(task, 0 , interval);
saveFile(in, request, task,fileUploadResults);
timer.cancel();
}
//保存文件
public void saveFile(InputStream in ,HttpServletRequest request,UploadRateTimerTask task,Map<String,String> fileUploadResults){
String line=null;
// String fileName=null;
// String fileSize = null;
// String uploadSize=null;
RandomAccessFile raf = null;
UploadRecord uploadRecord = null;
String fileMD5_client = null;
String fileMD5_server = null;
int blockSize = FileUploadUtil.getBlockSize();
try {
task.setTotal_uploadSize(0);
//先读到该文件的信息头“fileName=ddd&fileSize=xxx&uploadSize=aaa”
line = readLine(in);
if(line != null){
/*String[] info = line.split("&");
if(info != null && info.length>0){
for(String s: info){
if("fileName".equals(s.split("=")[0])){
fileName = s.split("=")[1];
}else if("fileSize".equals(s.split("=")[0])){
fileSize = s.split("=")[1];
}else if("uploadSize".equals(s.split("=")[0])){
uploadSize = s.split("=")[1];
}else if("fileMD5".equals(s.split("=")[0])){
fileMD5_client = s.split("=")[1];
}
}*/
uploadRecord = FileUploadUtil.getUploadRecoreFromString(line);
fileMD5_client = uploadRecord.getFileMD5();
HttpSession session = request.getSession();
String folder = session.getServletContext().getRealPath(UploadConfigConstants.UPLOAD_FILE);
String filepath = folder+File.separator + FileUploadUtil.getFileNameByUploadRecord(uploadRecord);
File file = new File(filepath);
if(! file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
if(! file.exists()){
file.createNewFile();
}
/**
* 先将properties文件放到临时文件夹下(tmep)
*/
String config_path = session.getServletContext().getRealPath(UploadConfigConstants.BREAK_POINT) + File.separator +
"temp/" + FileUploadUtil.getConfigFileNameByUploadRecord(uploadRecord);
File config_file = new File(config_path);
if(! config_file.getParentFile().exists()){
config_file.getParentFile().mkdirs();
}
if (! config_file.exists()) {
config_file.createNewFile();
}
raf = new RandomAccessFile(file, "rwd");
// if(file.length() != Long.parseLong(fileSize)){
// raf.setLength(Long.parseLong(fileSize));
// }
raf.setLength(uploadRecord.getFileSize());
//将读取文件的指针移动到断点位置
raf.seek(uploadRecord.getUploadSize());
//计算出从断点位置到文件结尾,还剩下的文件大小
long leftSize = uploadRecord.getFileSize()-uploadRecord.getUploadSize();
//本次上传,上传完成的文件大小
long completeSize = 0l;
/**
* 接下来是文件的内容
*/
int n=-1;
byte[] b = new byte[2048];
int total = 0;
int addSize = 0;
/*uploadRecord = new UploadRecord();
uploadRecord.setFileName(uploadRecord.getFileName());
uploadRecord.setFileSize(uploadRecord.getFileSize());
uploadRecord.setIp(request.getRemoteAddr());
uploadRecord.setUploadSize(Long.parseLong(uploadSize));*/
/**
* 在上传文件的时候,再去判断一下是否已经有程序在上传该文件
* 作为确认,防止万一
*/
boolean isStarted = false;
if(FileUploadUtil.isUploadStarted(request, uploadRecord)){
isStarted = true;
}
/**
* 为定时器动态绑定uploadRecord对象
*/
task.setUploadRecord(uploadRecord);
/**
* 判断文件从断点开始,还有多大文件需要传输,如果太小(小于 1 k )就要特殊处理
* 因为这时候不能使用 in.read(b) ,而只能使用 in.read(b,0,leftSize)
*/
if((completeSize + b.length) <= leftSize){
while((n=in.read(b)) != -1){
if(! isStarted){
raf.write(b,0,n);
total += n;
completeSize += n;
addSize += n;
task.setTotal_uploadSize(completeSize);
if(addSize >= blockSize){
FileUploadUtil.updateUploadSize(request, uploadRecord, addSize);
addSize = 0;
}
}
//判断是否已经到达最后一部分
if((completeSize + b.length) >= leftSize){
n = (int)(leftSize-completeSize);
问题就出在这里,因为客户端使用的是conn.setChunkedStreamingMode(10*1024);也就是块的概念,每次传输给服务器10*1024大小的内容,那么就可能会出现一个文件的最后一部分,被分在了两块里面,也就是分两次上传,这种情况下,in.read(b,0,n)就不能读取到n个字节的内容,而是少于n个,因此,这里需要获取到真正读取到的字节数:realNum = in.read(b, 0, n);然后判断(n-realNum)的大小,如果大于0,说明还没有读取完成,就需要循环,所以正确的方式应该如下:
/**
* 最后一部分特殊处理
*/
if((completeSize + b.length) >= leftSize){
int num = -1;
while(true){
/**
* num表示最后一部分还剩下多少
* n表示真正读取到的部分是多少
* n和num可能并不相同
*/
num = (int)(leftSize-completeSize);
n = in.read(b, 0, num);
completeSize += n;
if(! isStarted){
raf.write(b,0,n);
addSize += n;
task.setTotal_uploadSize(completeSize);
if(addSize >= blockSize){
FileUploadUtil.updateUploadSize(request, uploadRecord, addSize);
addSize = 0;
}
}
/**
* 如果leftSize == completeSize说明最后一部分处理完成
*/
if(leftSize == completeSize){
raf.close();
FileUploadUtil.updateUploadSize(request, uploadRecord, addSize);
addSize = 0;
//完成一个文件的上传,将该文件的完成百分比改为100%
task.setTaskComplete();
//完成一个文件的上传,将该文件的isStopped改为stopped
FileUploadUtil.setConfigFileStoped(request, uploadRecord);
fileMD5_server = MD5Util.getFileMD5String(file);
if(fileMD5_server != null && fileMD5_client != null){
if(fileMD5_server.equals(fileMD5_client)){
fileUploadResults.put(file.getName(), "OK");
/**
* 文件上传完成并且校验成功,则将其配置文件转移到已上传成功的文件夹
*/
FileUploadUtil.MoveFile(config_file, session.getServletContext().getRealPath(UploadConfigConstants.BREAK_POINT));
}
}else{
/**
* 文件上传完成,但是文件已损坏
*/
fileUploadResults.put(file.getName(), "DAMAGED");
}
readLine(in);
line = readLine(in);
if("------file begin------".equals(line)){
saveFile(in, request,task,fileUploadResults);
}
break;
}
}
}
而不是:
in.read(b, 0, n);
if(! isStarted){
raf.write(b,0,n);
total += n;
completeSize += n;
addSize += n;
raf.close();
task.setTotal_uploadSize(completeSize);
FileUploadUtil.updateUploadSize(request, uploadRecord, addSize);
addSize = 0;
//完成一个文件的上传,将该文件的完成百分比改为100%
task.setTaskComplete();
//完成一个文件的上传,将该文件的isStopped改为stopped
FileUploadUtil.setConfigFileStoped(request, uploadRecord);
fileMD5_server = MD5Util.getFileMD5String(file);
if(fileMD5_server != null && fileMD5_client != null){
if(fileMD5_server.equals(fileMD5_client)){
fileUploadResults.put(file.getName(), "OK");
/**
* 文件上传完成并且校验成功,则将其配置文件转移到已上传成功的文件夹
*/
FileUploadUtil.MoveFile(config_file, session.getServletContext().getRealPath(UploadConfigConstants.BREAK_POINT));
}
}else{
/**
* 文件上传完成,但是文件已损坏
*/
fileUploadResults.put(file.getName(), "DAMAGED");
}
file = null;
}
readLine(in);
line = readLine(in);
if("------file begin------".equals(line)){
saveFile(in, request,task,fileUploadResults);
}
break;
}
}
System.out.println(completeSize);
}else{//判断文件从断点开始,如果剩余文件太小(小于 1 k )就要特殊处理
in.read(b, 0, (int)leftSize);
if(!isStarted){
raf.write(b, 0, (int)leftSize);
}
raf.close();
task.setTotal_uploadSize(leftSize);
FileUploadUtil.updateUploadSize(request, uploadRecord, leftSize);
//完成一个文件的上传,将该文件的完成百分比改为100%
task.setTaskComplete();
//完成一个文件的上传,将该文件的isStopped改为stopped
FileUploadUtil.setConfigFileStoped(request, uploadRecord);
readLine(in);
line = readLine(in);
if("--file begin--".equals(line)){
saveFile(in, request,task,fileUploadResults);
fileMD5_server = MD5Util.getFileMD5String(file);
if(fileMD5_server != null && fileMD5_client != null){
if(fileMD5_server.equals(fileMD5_client)){
fileUploadResults.put(file.getName(), "OK");
}
}else{
fileUploadResults.put(file.getName(), "DAMAGED");
}
}else if("------complete------".equals(line)){
in.close();
in = null;
System.out.println("------complete------");
}
}
/**
* 文件上传完成,将状态修改为 “stoped”
*/
if(uploadRecord != null){
FileUploadUtil.setConfigFileStoped(request, uploadRecord);
}
}
// }
} catch (IOException e) {
/**
* 上传过程中出现异常,将状态修改为 “stoped”
*/
e.printStackTrace();
}finally{
/**
* 上传过程中出现异常,将状态修改为 “stoped”
*/
if(uploadRecord != null){
FileUploadUtil.setConfigFileStoped(request, uploadRecord);
}
if(raf != null){
try {
raf.close();
} catch (IOException e1) {
e1.printStackTrace();
}
raf = null;
}
}
}
/**
* 读取一行内容
*/
private String readLine(InputStream in) {
return FileUploadUtil.readLine(in);
}
}
这个问题的解决让我进一步明白,出现问题的时候,尽量从自己身上找问题,这才是正道