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); } }
这个问题的解决让我进一步明白,出现问题的时候,尽量从自己身上找问题,这才是正道