自己编写JAVA环境下的文件上传组件  
上传文件是经常用到的,B/S环境下的文件上传原理其实和带附件的Email一样,HTTP数据流 由标志性的数据加上文件数据组成,你只要得到数据流将其标志性数据去掉,剩下的就是你 的数据文件了,在将其写成文件就完成了上传。 
下面我们分布说明: 
1.上传文件的静态页面,我们一定要确认method="post" enctype="multipart/form-data"  为什么就不要说了吧。 
<%@ page contentType="text/html; charset=GBK" %> <html> <head> <title> browsefile </title> </head> 
<body> <h1> test2 </h1> <FORM method="post" enctype="multipart/form-data" action="iFileUpload.jsp" > <INPUT name="filea" type="file"><BR> <INPUT name="btnval" type="submit" value="上载"> <INPUT type="reset" value="重置">  </FORM> 
</body> </html> 
客户端上传后,服务器端的数据流头尾部格式如下,这里上传了一个Word文档 
我们看看数据流的头部: 
-----------------------------7d22f821706e0Content-Disposition: form-data;  name="filea"; filename="C:\工作流管理系统总体设计.doc"Content-Type:  application/msword 邢唷??......     (注意这里是数据文件开始的地方) .................................... 
尾部标志: 
-----------------------------7d22f821706e0Content-Disposition: form-data;  name="btnval"  上载-----------------------------7d22f821706e0-- 
所以去掉头尾部标志性数据我们就得到上传的文件数据了。 
 下面我们看看处理上传的Bean:uploadBean 首先得到初始化Bean得到上下文环境: 
public final void initialize(PageContext pageContext)         throws ServletException     {         m_application = pageContext.getServletContext();         m_request = (HttpServletRequest)pageContext.getRequest();         m_response = (HttpServletResponse)pageContext.getResponse();     } 
    将数据流写到一个BYTES数组中,数组大小就是REQUEST流的大小。 
 m_totalBytes = m_request.getContentLength();  m_binArray = new byte[m_totalBytes];  for(; totalRead < m_totalBytes; totalRead += readBytes)             try             {                 m_request.getInputStream();                 readBytes = m_request.getInputStream().read(m_binArray, totalRead, m_totalBytes - totalRead);             }             catch(Exception e)             {                 System.out.println(" Unable to upload data .");                 e.printStackTrace();             } 2。下面就开始处理BYTES数组 
以前我见到有网友的作法将m_binArray直接转化成String,然后利用String的方法去掉标志 位数据 
 String newstr=new String(m_binArray); 
这一方法我试过了,是行不通的,我不知道它们测试过程序没有,对于上传文本文件应该没问题 如果上传的是WORD文档或者图片等二进制文件,进行转化成字符串的时候数据就会有丢失,我想 可能是因为编码的原因造成的,所以不能直接转换。 
正确的方法是将字节数组的每一位转化成CHAR或判断ASCII码值来判断头尾标志为数据: 
for(; !found && m_currentIndex < m_totalBytes; m_currentIndex++)             {                 if(m_binArray[m_currentIndex] == 13)                     found = true;                 else                     m_boundary = m_boundary + (char)m_binArray[m_currentIndex];             }             if(m_currentIndex == 1)                 return;             m_currentIndex++;             do             {                 if(m_currentIndex >= m_totalBytes)                     break;                 dataHeader = getDataHeader();                 System.out.println(dataHeader);                 m_currentIndex = m_currentIndex + 2;                 isFile = dataHeader.indexOf("filename") > 0;                                  getDataSection();                 if(isFile)                 {                     ////                   System.out.println("----->m_startData:"+m_startData);                   System.out.println("----->m_endData:"+m_endData);                   try                   {                     fileout = new FileOutputStream("c:\\test11.doc");                     fileout.write(m_binArray,m_startData,m_endData-m_startData+1);                     fileout2 = new FileOutputStream("c:\\test00.doc");                     fileout2.write(m_binArray);                   }                   catch(Exception e)                   {                     System.out.println(" Unable to write data to test file .");                     e.printStackTrace();                   }                   finally                   {                     try                     {                       fileout.close();                       fileout2.close();                     }                     catch(Exception e)                     {                       e.printStackTrace();                     }                   }                 } 
private String getDataHeader()         {             int start = m_currentIndex;             int end = 0;             int len = 0;             boolean found = false;             while(!found)                 if(m_binArray[m_currentIndex] == 13 && m_binArray[m_currentIndex + 2] == 13)                 {                     found = true;                     end = m_currentIndex - 1;                     m_currentIndex = m_currentIndex + 2;                 }                 else                 {                     m_currentIndex++;                 } 
            String dataHeader = new String(m_binArray, start, (end - start) + 1);             return dataHeader; 
} 
private void getDataSection()         {             boolean found = false;             String dataHeader = new String();             int searchPos = m_currentIndex;             int keyPos = 0;             int boundaryLen = m_boundary.length();             m_startData = m_currentIndex;             m_endData = 0;             do             {                 if(searchPos >= m_totalBytes)                     break;                 if(m_binArray[searchPos] == (byte)m_boundary.charAt(keyPos))                 {                     if(keyPos == boundaryLen - 1)                     {                         m_endData = ((searchPos - boundaryLen) + 1) - 3;                         break;                     }                     searchPos++;                     keyPos++;                 }                 else                 {                     searchPos++;                     keyPos = 0;                 }             }             while(true);             m_currentIndex = m_endData + boundaryLen + 3;     } 
  
m_currentIndex为当前字节数组的指针位置,先得到HEADER数据,见方法getDataHeader() 然后在得到文件数据开始的指针位置和SIZE,见方法getDataSection() 然后,将数据流写到文件里: fileout.write(m_binArray,m_startData,m_endData-m_startData+1); 就得到了完整的数据文件,上面test00.doc 和 test11.doc 是去掉标志数据前后的数据流 分别写成的文件,大家用二进制查看程序可看出其中的差别。 
以上getDataHeader(),getDataSection()是我参考了SMARTUPLOAD的实现原理, 其中分析标志数据位的方法稍有复杂,网友可自己去分析。程序在TOMCAT下测试通过, 上传WORD文档和图片都没问题。 
  
  
  
  
   
 
  |