`
nakupanda
  • 浏览: 416807 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

JSP上传问题的研究

    博客分类:
  • java
阅读更多
原文时间:2007-10-11


[版权:badboy.net.cn]


因为是初学者,所以在我需要JSP为我提供上传功能的时候,我应该去了解一下实现细节,当我了解足够的时候,去使用别人的组件,或者给别人提供组件。





我首先是了解一下能用request.getInputStream()得到的数据是什么样子的:

1、新建一个HTML页面,含以下表单,用于选择和提交要上传的文件:
<form method="post" action="upload.jsp" ENCTYPE="multipart/form-data">
  <input type="file" name="file1" />
  <input type="submit" value="submit" />
</form>




2、
新建一个JSP页面upload.jsp:
<%@ page contentType="text/html;charset=UTF-8"%>
<%@ page import="java.io.*"%>
<%
try
{
 File file = new File("e:/upfile.txt");
 InputStream is = request.getInputStream();
 FileOutputStream fos = new FileOutputStream(file);
 int rn;
 byte[] buf = new byte[1024];
 while((rn=is.read(buf,0,1024))!=-1)
   fos.write(buf,0,rn);
 
 is.close();
 fos.close();
}
catch(Exception e)
{
 
}
%>



这样,打开HTML页面选择文件并提交后,如无意外E:/下会多出一个upfile.txt文件,它的内容为:

清单1


1  -----------------------------7d65d38307d2
2  Content-Disposition: form-data; name="body3"; filename="C:\Documents and Settings\badboy\桌面\复件 (3) 新建 文本文档.txt"
3  Content-Type: text/plain
4
5  dasfdf
6  sdf
7  asdf
8  -----------------------------7d65d38307d2--


可以了解到:
1、1个文件被2个“-----------------------------7d65d38307d2”夹着
2、第2行到第4行是文件描述
3、文件内容由第5行开始,直到出现“-----------------------------7d65d38307d2”
4、第一行和最后一行的字符串很像,都是“-----------------------------7d65d38307d2”,最后一行多了“--”

因为考虑到上传的可能不是文本文件,但文件描述和分割线却是文本,所以全部用字符串读写方法分析应该行不通,受一本JSP教程的例子启发,决定用RandomAccessFile
RandomAccessFile 可以在文件内的任何位置随意跳转,并且可以读写字符串和字节,因而可以在以字符串方式分析到文件内容的起始位置和结束位置后很方便的跳转到适当位置再以字节方式读取和生成文件。


以下是一个例子,新建一个JSP文件,内容为

<%@ page contentType="text/html;charset=UTF-8"%>
<%@ page import="java.io.*"%>
<%
try
{
File fl1 = new File("e:/upfile.txt");  //这个是刚才那个文件a
File fl2 = new File("e:/upfile2.txt");  //这个将是内容跟上传的那个文件一模一样的文件b
RandomAccessFile raf1 = new RandomAccessFile(fl1,"r");  //只读文件a 的 RandomAccessFile对象用来在upfile.txt里读出数据用来分析和生成文件
RandomAccessFile raf2 = new RandomAccessFile(fl2,"rw");  //这个是用于生成目的文件的RandomAccessFile对象
String StringStart = null;  //upfile.txt的第一行(“-----------------------------7d65d38307d2”) 是分割符
String tmpStr = null;  //要来临时存放一些字符串
long startPos = 0 ;  //实际文件内容的起始位置
long endPos = 0;  //实际文件内容的结束位置


StringStart = raf1.readLine();  //读取第一行即分割符
raf1.readLine();
raf1.readLine();
raf1.readLine();
  //连续4次调用readLine()方法,使文件指针跳到了清单1 的第4行的开始位置,即实际文件的起始位置
startPos = raf1.getFilePointer();  //获得实际文件内容的起始位置


  //以下这个while循环在找到下一个类似“-----------------------------7d65d38307d2”的时候分割符退出,并且会计算实际文件内容的结束位置
while((tmpStr=raf1.readLine())!=null)
{
 if(tmpStr.indexOf(StringStart)!=-1)
 {
  out.print("found.");
  endPos = raf1.getFilePointer() - tmpStr.getBytes().length - 2;  //获得实际文件内容的结束位置
  break;
 }
}


raf1.seek(startPos);  //将指针重新定位到实际文件内容的起始位置  现在已经知道实在文件内容在哪里开始哪里结束了


  //以下这个while循环将读取实际文件内容的起始位置到结束位置间的内容到upfile2.txt中理论上upfile2.txt的内容是上传的文件的内容一模一样的
while(startPos<endPos)
{
 raf2.write(raf1.readByte());
 startPos = raf1.getFilePointer();
}
raf1.close();
raf2.close();
}
catch(Exception e)
{

}
%>




上传一个文件的解决方法大概就是这样子,应该很好理解的,不过有几个问题:

1、怎样处理多个文件?
2、性能



关地第1个问题:
只要重复查找分割符并作一些类似的处理可以解决,以后有例子;

关于第2个问题:
我发现程序处理的时间大多是用于文件分析而不是文件的传输过程(我在本机测试传输过程用的时候可以忽略),而用于文件分析的时间我想大多是用在文件内部跳转的操作上,后来我用一个字节buffer读代替一个一个字节读和写速度有很大提高,但是处理5个共20M左右的MP3文件耗时比较多,这还是在本机上测试的。

以下是我做的一个JavaBean,我想大概不太符合某些规范,不过的确可以实现多文件上传:

下载地址:http://www.badboy.net.cn/badboy/bnc_fpr.rar
方法说明:http://www.badboy.net.cn/badboy/MethodSummary.html


实际上它只负责文件的分析.

以下是一个应用例子,一个包括了表单的JSP页面:


<%@ page contentType="text/html;charset=UTF-8"%>
<%@ page import="java.io.*"%>
<%@ page import="cn.net.badboy.FileParser"%>
<jsp:useBean id="fpr" scope="page" class="cn.net.badboy.FileParser" />

<%
String action=request.getParameter("action");
if(action==null)
 action="";
if(action.equals("save"))
{
 String FilePath = request.getRealPath("/") + "uploadfiles";  //设置上传文件的保存目录这里是jsp页面所在目录中的uploadfiles目录如果没有这个目录请手动为它新建一个
 InputStream is = request.getInputStream();
 File f = new File("e:/jt.bnc");  //临时文件即包含分割符、文件描述和文件内容的那个文件
 if(f.exists())
 {
  f.delete();
  f = new File("e:/jt.bnc");
 }
 FileOutputStream fos = new FileOutputStream(f);
 int rn;
 byte[] buf = new byte[1024];
 while((rn=is.read(buf,0,1024))>0)
 {
  fos.write(buf,0,rn);
 }
 
 is.close();
 fos.close();
  //到这里临时文件生成了余下的工作不再是从客户那里传输文件而是服务器方面的文件分析工作
                
                
                 
 
 fpr.parseFile(f,FilePath,"mp3,gif,jpg");  //方法parseFile分析一个临时文件第一个参数指明临时文件对象第二个参数指明生成的文件的保存目录第三个参数指明充许的文件类型
 out.println("Errors message :<br>"+fpr.getErrorMessage()+"<br>");  //方法getErrorMessage返回文件分析过程中的错误例如有扩展名不合法的文件等
 String[] FileNames = fpr.getFileNames();  //方法getFileNames返回一个存放了成功上传的文件的文件名的字符串数组
 out.println("file uploaded:<br>");
 for(int i=0;i<FileNames.length;i++)
  out.println(FileNames[i]+"<br>");
}
else
{
%>
<form method="post" action="?action=save"  ENCTYPE="multipart/form-data">
<input type="file" name="body1" />
<input type="file" name="body2" />
<input type="file" name="body3" />
<input type="file" name="body4" />
<input type="submit" value="submit" />
</form>
<br />
<%
}
%>






以下是bean cn.net.badboy.FileParser全部代码,有兴趣的朋友可以看看:

package cn.net.badboy;
import java.io.*;

 

/*
don't remove this message .
this bean from www.badboy.net.cn .
please ! don't remove this message .
all copyright reserved by www.badboy.net.cn .
ar ... don't remove this message .
*/


public class FileParser
{
 private String[] FileNameArray = new String[20] ;     //this array  stores files' name that have been create .
 private int FileCount = 0 ;          //tells how many file are there
 private String errorMessage = "" ;

 

//***********************************private method definition begin*******************************************************

 //method setErrorMessage(String msg)
 private void setErrorMessage(String errorMessage)
 {
  this.errorMessage += "\n" + errorMessage ;
 }


 private boolean createFile(RandomAccessFile SourceFile,long startPos,long endPos,String FileDirectory,String FileName)
 {
  File file = null;
  RandomAccessFile targetFile = null;
  try{
   file = new File(FileDirectory,FileName);
   if(file.exists())      //if the file exists,overwrite it.
   {
    file.delete();
    file = new File(FileDirectory,FileName);
   }
   targetFile = new RandomAccessFile(file,"rw");
   
   int rn;
   int bufferSize = 1024 ;
   byte[] buf = new byte[bufferSize];

   while(startPos<endPos)
   {
    if(startPos+bufferSize>=endPos)
    {
     targetFile.write(SourceFile.readByte());
     startPos = SourceFile.getFilePointer();     
    }
    else
    {
     rn = SourceFile.read(buf,0,bufferSize);
     targetFile.write(buf,0,rn);
     startPos = SourceFile.getFilePointer(); 
    }
   }
  }
  catch(Exception e)
  {
   e.printStackTrace();
   return false ;
  }
  finally{
   try{ 
     if(targetFile!=null)
     {
      targetFile.close();
     }
    }
   catch(IOException e)
   {
    e.printStackTrace();
    return false;
   }
  }
  return true ;
 }
 
 private String getFileName(String NameInJerk,String allowableFiles) throws Exception
 {
  NameInJerk = new String(NameInJerk.getBytes("ISO-8859-1"),"UTF-8") ;     //encoding to local charset
  int startPos = NameInJerk.lastIndexOf("\\");
  
  if(startPos==-1)
   return null ;
  String FileName = NameInJerk.substring(startPos+1,NameInJerk.length()-1);
  String[] TmpArr = FileName.split("\\.");
  String FileTypeName = TmpArr[TmpArr.length - 1];
  if(allowableFiles.indexOf(FileTypeName)==-1)
  {
   setErrorMessage("file " +  FileName + " is not a supported type of file to upload , upload failed .");
   return null ;
  }
  return FileName;
 }
 
 

 
 
 private static void debug(String message)
 {
  System.out.println(message);
  
  //or log sth
 }
//************************end private method definition******************************************* 
 
 
 
//*************************here begin the public method definition ******************************
 
 
 
 //method getErrorMessage()
 //return the error message
 public String getErrorMessage()
 {
  return errorMessage ;
 }
 
 //public METHOD parseFile
 //parseFile接受参数TmpFileName(临时文件)解析临时文件,在FileDirectory(生成文件目录)生成约干文件 return true if success , or not false returned instead. 
 public boolean parseFile(File TmpFile,String FileDirectory,String allowableFiles)
 {
  String CompartString = null ;   //分割字符串通常为临时文件第一段内容
  String TmpString     = null ;   //临时字符串
  String FileName = null ;  //保存文件名
  long startPos = 0 ;   //每个文件内容的开始位置
  long endPos   = 0 ;   //每个文件内容的结束位置
  RandomAccessFile SourceFile = null ;
  
  try{
   debug("starting.......");
   SourceFile = new RandomAccessFile(TmpFile,"r") ;  //创建随机读取文件对象
   CompartString = SourceFile.readLine();   //获得分割字符串
   SourceFile.seek(0);   //将操作位置重定位到文件开头
   
   looper1:
   while(true)
   { 
    while((TmpString=SourceFile.readLine())!=null){
     if(TmpString.indexOf(CompartString)!=-1){ 
      for(int i=1;i<=3;i++)
      { 
       TmpString = SourceFile.readLine();
       if(TmpString==null)
        break looper1;
       if(i==1)
        FileName  = getFileName(TmpString,allowableFiles);   //第二行包含文件名等信息可以获得文件名
      }
     if(FileName!=null)
      break;
     }
    }
    
    debug("parsing...");
    startPos = SourceFile.getFilePointer();    //获得文件内容的起始位置
    
    
    while((TmpString=SourceFile.readLine())!=null)
    {
     if(TmpString.indexOf(CompartString)!=-1)
     {
      endPos = SourceFile.getFilePointer() - TmpString.getBytes().length - 2 ;   //得到文件内容的结束位置
      break;
     }
    }
    SourceFile.seek(startPos);   //将操作位置重定位到startPos处开始生成一个文件
    createFile(SourceFile,startPos,endPos,FileDirectory,FileName);   //invoke生成文件方法生成文件
    startPos = endPos + 2 ; 
    debug("done...");
    
    // add a file name to FileNameArray
    FileNameArray[FileCount++] = FileName ; 
    FileName = null ;
   }
   
  }
  catch(Exception e)
  {
   e.printStackTrace();
   return false ;
  }
  finally{
   try{
    if(SourceFile!=null)
    {
     SourceFile.close();
     TmpFile.delete();   //delete tmpfile    maybe is should be deleted by who create it .
    }
    
   }
   catch(IOException e)
   {
    e.printStackTrace();
    return false;
   }
  }
  return true;
 }
 
 //public METHOD getFileNames()
 //return an array storing some file name which was created . if it doesn't contains anything,the returned arrary length will be 0 .
 public String[] getFileNames()
 {
  String[] FileNameArray = new String[FileCount];
  try{
    for(int i=0;i<FileCount;i++)
    {
     FileNameArray[i] = this.FileNameArray[i];
    }
  }
  catch(Exception e)
  {
    e.printStackTrace();
    return FileNameArray;
  }
  return FileNameArray ;
 }
 
 public int getFileCount()
 {
  return FileCount;
 }
 
 
 //this operation may modify the file has been created . return false if no such file found or some error caused.
 //arguments should contains file directory .
 public boolean setFileName(String oldFileName,String newFileName) 
 {
  try
  {
   File oldFile = new File(oldFileName);
   File newFile = new File(newFileName);
   oldFile.renameTo(newFile);
   oldFileName = oldFile.getName();
   newFileName = newFile.getName();

   for(int i=0;i<FileCount;i++)
   {
     if(FileNameArray[i].equals(oldFileName))
      FileNameArray[i] = newFileName;
   }
   
  }
  catch(Exception e)
  {
   e.printStackTrace();
   return false ;
  }
  return true ;
 }
}






我想性能的问题是出在指针的seek来seek去

希望同学们把自己的想法和大家分亨
分享到:
评论
2 楼 ouyangfei0426 2011-04-26  
  //以下这个while循环在找到下一个类似“-----------------------------7d65d38307d2”的时候分割符退出,并且会计算实际文件内容的结束位置  
while((tmpStr=raf1.readLine())!=null)  
{  
 if(tmpStr.indexOf(StringStart)!=-1)  
 {  
  out.print("found.");  
  endPos = raf1.getFilePointer() - tmpStr.getBytes().length - 2;  //获得实际文件内容的结束位置  
  break;  
 }  
}

楼主这里是不是有点问题,你的StringStart应该是-----------------------------7d65d38307d2,它后面的回车换行符,你给忽视掉了,也就是说
StringStart应该是字符串“-----------------------------7d65d38307d2”+回车换行,而你都到最后一个终结符的时候是“-----------------------------7d65d38307d2--”+回车换行符。
所以你这个判断条件tmpStr.indexOf(StringStart)!=-1在你上面的代码应该是不会有为true的时候的。
1 楼 ouyangfei0426 2011-04-26  
楼主考虑的比我多,我目前限于水平,并没有考虑关于性能方面的问题。呵呵,但是好像楼主并没有考虑到表单还有其他表单元素的情况

相关推荐

    jsp上传文件Demo

    【JSP上传文件Demo】是基于Java服务器页面(JSP)技术实现的一种文件上传功能的示例。在Web开发中,文件上传是一个常见的需求,例如用户上传头像、提交附件等。`SmartUpload`是一个流行的Java库,专门用于处理文件...

    JSP文件上传 支持进度条显示.rar

    7. **异常处理和错误提示**:在文件上传过程中可能出现各种问题,如网络中断、文件格式错误等,项目应该有完善的异常处理机制,并向用户清晰地显示错误信息。 8. **安全性考虑**:文件上传可能存在安全风险,比如...

    JSP同时选择多文件上传MultifileUploadDemo

    通过深入研究这个示例,开发者可以掌握如何处理复杂的文件上传需求,提高Web应用的功能性和用户体验。同时,随着HTML5的普及,现代浏览器已经支持多文件上传API,开发者也可以考虑使用纯HTML5的方案,避免对Flash的...

    JSP无组件文件上传

    在网络上找到的,纯JSP实现的文件上传程序,支持多文件的上传,例子是多文件的上传,稍微修改就可以变成单文件的上传或者更多文件的上传,控制成需要扩展名的文件上传,指定大小的文件上传等。程序目前上传文件存储...

    JSPUpload.rar_JSP上传_jsp 上传 图_jsp 图片 上传_jspupload_上传图片到数据库

    在描述中提到,“jsp上传图片到数据库的列子,里面的带有文字的描叙,很清晰”,这意味着压缩包中的文档提供了步骤清晰的教程或案例研究,指导用户如何利用JSP处理图片上传并将其存储到数据库中。通常,这一过程包括...

    jsp异步上传文件

    解压并研究这些文件可以帮助你更好地理解异步文件上传的具体实现。 总的来说,`jsp异步上传文件`结合了JSP、Servlet和JavaScript的ajaxFileupload.js,构建了一个高效、用户体验良好的文件上传解决方案。这个过程中...

    ueditor jsp 图片上传demo

    作者通过自己的研究和实践,创建了一个能够工作的图片上传功能,并愿意分享给其他开发者,帮助他们节省时间和精力。 【标签】"ueditor"是富文本编辑器的名字,它提供了丰富的文本格式化选项,如插入图片、链接、...

    jsp上传文件带进度条(源码项目)

    综上所述,这个"jsp上传文件带进度条(源码项目)"展示了如何使用JSP、Java Servlet和JavaScript技术实现无刷新的文件上传功能,提供丰富的上传进度反馈,提升了用户体验。对于开发者来说,这是一个学习和研究文件上传...

    JSP上传下载组件 包含源码及帮助文档

    **JSP上传下载组件**是Web开发中常用的一种工具,用于在服务器端处理用户通过浏览器上传的文件,以及提供文件的下载服务。本组件名为"jspsmartupload",提供了完整的源码和帮助文档,方便开发者理解和应用。下面将...

    jsp图片上传完整示例

    在IT行业中,网页应用开发经常会涉及到用户交互,如文件上传功能。本示例"jsp图片上传完整示例"就是一种实现此类功能的实际操作,它基于...开发者可以通过研究这个示例,掌握如何在实际项目中实现类似的文件上传功能。

    android与jsp上传图片

    在Android与JSP之间进行图片上传是一个常见的网络通信任务,主要涉及到客户端(Android应用)与服务器端(JSP)的数据交互。在这个过程中,Android...通过深入研究这些代码,可以更好地理解和实践图片上传的整个流程。

    JSP上传下载jar

    找了好几天的资料,终于研究成功,jspSmartUpload.jar 上网找了好多资料都不能解决下载有中文的文件,最后加入自己一个下载的class文件,实现了能下载中文文件的类.这样就能上传,也能下载所有文件了.用法比原来的还...

    ajax+jsp上传程序加进度条.zip

    【标题】"ajax+jsp上传程序加进度条.zip"是一个基于AJAX技术与JSP(JavaServer Pages)的文件上传程序,它包含了实现文件上传功能的详细源代码。该程序的特点在于提供了一个友好的用户体验,即在上传过程中显示...

    JSP多个文件上传源代码程序

    【标题】"JSP多个文件上传源代码程序"揭示了一个重要的Web开发技术,即在JavaServer Pages ...通过研究这个源代码,开发者可以深入理解JSP环境下的文件上传机制,并能应用到自己的项目中,提高应用的功能性和安全性。

    jsp上传文件和下载文件

    最近做图片上传,研究了一下上传组件,最后决定用了smartUpload,但是遇到了一些小问题 1.中文字符的处理 smartUpload作者是不是比较懒还是就只是为英语国家的人使用,尽然没有转换字符集的方法,因此自己读读源码...

    带进度条的JSP文件上传程序.rar

    本项目“带进度条的JSP文件上传程序”提供了一个高效的解决方案,它结合了JSP和AJAX技术,允许用户在上传过程中看到实时的进度条反馈,提升了用户体验。 首先,JSP(JavaServer Pages)是一种动态网页技术,基于...

    宏软JSP上传系统 v1.0

    了解了这些基本概念后,开发者可以进一步研究源代码,深入理解宏软JSP上传系统的实现细节,包括其使用的JSP标签库、Servlet技术、以及如何利用Java后端处理文件上传的逻辑。此外,对于系统优化和扩展,开发者还需要...

    超漂亮的extjs界面的JSP图片上传系统.rar

    《超漂亮的ExtJS界面JSP图片上传系统详解》 在当今的Web开发中,用户界面的设计与用户体验息息相关,一个美观且功能完善的上传系统是提升网站吸引力的重要元素。本篇文章将详细解析“超漂亮的ExtJS界面的JSP图片...

    jsp实现附件上传功能源码-基础源码

    "jsp实现附件上传功能源码-基础源码" 这个标题指出,我们关注的是一个使用JSP技术实现的附件上传功能。JSP(JavaServer Pages)是Java平台上的一种动态网页技术,它允许开发人员在HTML页面中嵌入Java代码,以实现...

    jspsmart实现上传下载

    **JSpsmart** 是一个基于Java的开源上传和下载组件,它为Web应用程序提供了一种高效、稳定且易于使用的文件上传和下载功能。这个组件在Web开发中特别有用,因为它处理了与大文件上传和断点续传相关的复杂性。 **...

Global site tag (gtag.js) - Google Analytics