`
nakupanda
  • 浏览: 410497 次
  • 性别: 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无组件文件上传

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

    JSP上传下载jar

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

    基于jsp的带进度条的文件上传

    基于jsp的文件上传、非常适合研究上传功能

    jsp实现图片上传功能

    对于jsp上传图片问题,研究了一段时间,也差了好多资料,最近终于搞定一个,供大家下载测试。

    jsp上传文件和下载文件

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

    servlet+jsp上传下载

    这是一个servlet+jsp做的上传下载项目,供大家学习交流!!绝对可以跑起来!!!欢迎大家加我好友!!共同研究java

    jsp文件上传实例以及配置详细讲解

    网上很多版本的组件都是会出现乱码,我这个已经解决了乱码问题,下载看到的是正常中文。欢迎大家踊跃下载,共同研究。

    [上传下载]宏软JSP上传系统 v1.0_hrjspup10.zip项目JAVA源码+资料打包下载

    [上传下载]宏软JSP上传系统 v1.0_hrjspup10.zip项目JAVA源码+资料打包下载[上传下载]宏软JSP上传系统 v1.0_hrjspup10.zip项目JAVA源码+资料打包下载 1.适合学生做毕业设计参考 2.适合个人学习技术研究参考 3.适合小...

    [上传下载]宏软JSP上传系统 v2.0完美版_upload-v2.zip项目JAVA源码+资料打包下载

    [上传下载]宏软JSP上传系统 v2.0完美版_upload-v2.zip项目JAVA源码+资料打包下载[上传下载]宏软JSP上传系统 v2.0完美版_upload-v2.zip项目JAVA源码+资料打包下载 1.适合学生做毕业设计参考 2.适合个人学习技术研究...

    JSP上传文件的好例子

    上传文件的好例子,有兴趣的可以研究下

    JSP extjs upload 上传程序.rar

    JSP extjs upload 上传程序,EXT版本2.2,给学习JSP下使用AJAX的朋友一个参考,程序部分地方有些小毛病,不影响使用,本人也是在学习研究中。

    [上传下载]仿163网盘无刷新文件上传 for Jsp_fileupload_jsp.zip项目JAVA源码+资料打包下载

    [上传下载]仿163网盘无刷新文件上传 for Jsp_fileupload_jsp.zip项目JAVA源码+资料打包下载[上传下载]仿163网盘无刷新文件上传 for Jsp_fileupload_jsp.zip项目JAVA源码+资料打包下载 1.适合学生做毕业设计参考 2....

    JSP上传图片并缩放裁切的程序

    内容索引:JSP源码,上传下载,图片裁切,JSP上传文件 版、JS版的图片裁切功能,但是没找到JAVA方面的,试着做了一个,正在这方面研究的朋友可以做个参考。它包括两部分,一部分上传图片,另一部分对图片进行处理,缩放...

    上传下载宏软JSP上传系统 v1.0-hrjspup10.rar

    功能在确认正常工作后才上传。【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来...

    jsp文件上传的例子

    一个上传的小例子。一直没有研究透,放上来给大家看看

    安卓图片上传和文件上传带jsp服务端源码.zip项目安卓应用源码下载

    安卓图片上传和文件上传带jsp服务端源码.zip项目安卓应用源码下载安卓图片上传和文件上传带jsp服务端源码.zip项目安卓应用源码下载 1.适合学生毕业设计研究参考 2.适合个人学习研究参考 3.适合公司开发项目技术参考

    计算机毕业设计(2)——JSP(52套)

    由于上传不能超过220M,100多个项目分了两批,这是第二批,项目列表如下: JSP企业电子投票系统(源代码+论文+开题报告+外文翻译+文献综述); JSP企业电子投票系统(源代码+论文+开题报告+文献综述); JSP企业人事管理...

    [上传下载]宏软JSP上传系统 v1.0_hrjspup10.rar

    功能在确认正常工作后才上传。【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来...

    安卓图片上传和文件上传带jsp服务端源码.zip安卓程序项目源码资源下载

    安卓图片上传和文件上传带jsp服务端源码.zip安卓程序项目源码资源下载安卓图片上传和文件上传带jsp服务端源码.zip安卓程序项目源码资源下载 1.适合学生做毕业设计用 2.适合程序员学习研究用 3.适合小公司换皮做新...

    Android应用源码之安卓图片上传和文件上传带jsp服务端源码.zip项目安卓应用源码下载

    Android应用源码之安卓图片上传和文件上传带jsp服务端源码.zip项目安卓应用源码下载Android应用源码之安卓图片上传和文件上传带jsp服务端源码.zip项目安卓应用源码下载 1.适合学生毕业设计研究参考 2.适合个人学习...

Global site tag (gtag.js) - Google Analytics