我下载了jspsmartupload类,然后编写了下载程序,如下: <%@page contentType="text/html;charset=gb2312"%>;<%@page language="java" import="com.jspsmart.upload.*"%>;<jsp:useBean id="mySmartUpload" scope="page" class="com.jspsmart.upload.SmartUpload"/>;<%mySmartUpload.initialize(pageContext); mySmartUpload.downloadFile("d:\\111.txt"); %>; 运行后,我txt文件中的内容就直接显示在了页面上,zip文件也同样,只不过是乱码,有什么办法不显示而和一般的下载一样呢?
eclipse 回复于:2002-10-18 10:54:22
应该是SmartUpload类的问题,JSP程序没有问题,我感觉
huangmw 回复于:2002-10-18 11:27:17
这个类是从www.jspsmart.com站点下载的,不会他们编的类问题吧? 你能提供一个类似这种类给我吗?谢谢了
eclipse 回复于:2002-10-18 12:11:30
TestFileDownload.JSP页面的例子:
<% // 得到文件名字和路径 String filename = ”MengxianhuiDocTest.doc”; String filepath = ”D:\\”;
// 设置响应头和下载保存的文件名 response.setContentType(”APPLICATION/OCTET-STREAM”); response.setHeader(”Content-Disposition”, ”attachment; filename=\”” + filename + ”\””);
// 打开指定文件的流信息 java.io.FileInputStream fileInputStream = new java.io.FileInputStream(filepath + filename);
// 写出流信息 int i; while ((i=fileInputStream.read()) != -1) { out.write(i); } fileInputStream.close(); out.close(); %>;
值得注意的是:在你要下载的文件内容里,除了文件的内容之外,不应该再附加有其它任何的字符,包括空格和回车换行符。我们有时在编写代码的时候,为了使代码清晰可读,往往会添加一些空格、制表符或者回车换行符,这样虽然看起来比较清晰,但有时可能会得不到正确的结果。比如: <%@ page import=”java.io.*” %>; <jsp:useBean id=”MyBeanFromMengxianhui” scope=”page” class=”com.Mengxianhui.DownloadBean” />; 应该写成这样: <%@ page import=”java.io.*” %>;<jsp:useBean id=”MyBeanFromMengxianhui” scope=”page” class=”com.Mengxianhui.DownloadBean” />;
eclipse 回复于:2002-10-18 12:13:21
请注意:APPLICATION/OCTET-STREAM是设置下载类型
要改成你实际的类型,如excel要写成:application/vnd.ms-excel
eclipse 回复于:2002-10-18 12:17:39
如果不用jspsmart,你就需要了解浏览器端的编码方式,在传到服务器端时你才能解码。也才可以得到上传文件的相关信息。看下面的代码。 package mshtang.fileUpload; import java.io.*; /**一个存放文件信息的类,包括文件的名称(String), **字段名(String), Content-Type(String)和内容(byte[]) **还提供了一个直接将文件内容保存到一个文件的函数 void saveTo(File f) **可以调用 类{@link ContentFactory}中的适当方法,生成该类的实例。 ** @see ContentFactory ** @see ContentFactory#getFileParameter ** @see ContentFactory#getFileParameterValues **/
public class FileHolder { String contentType; byte[] buffer; String fileName; String parameterName;
FileHolder(byte[] buffer, String contentType, String fileName, String parameterName) { this.buffer = buffer; this.contentType = contentType; this.fileName = fileName; this.parameterName = parameterName; } /**把文件的内容存到指定的文件中, **<b>;这个方法不会检查这个文件是否可写、是否已经存在。</b>; **@param file 目的文件 **@throws 在 I/O 操作中被抛出的 IOException **/ public void saveTo(File file) throws IOException { BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file)); out.write(buffer); out.close(); }
/**把文件的内容存到指定的文件中, **<b>;这个方法不会检查这个文件是否可写、是否已经存在。</b>; **@param name 目的文件名 **@throws 在 I/O 操作中被抛出的 IOException **/ public void saveTo(String name) throws IOException { saveTo(new File(name)); }
/** **返回一个文件内容的字节数组 **@return 一个代表文件内容的字节数组 **/ public byte[] getBytes() { return buffer; }
/** **返回该文件在文件上载前在客户端的名称 **@return 该文件在文件上载前在客户端的名称 **/ public String getFileName() { return fileName; }
/** **返回该文件的 Content-Type **@return 该文件的 Content-Type **/ public String getContentType() { return contentType; }
/** **返回上载该文件时,Html 页面窗体中 file 控件的 name 属性 **@return 返回上载该文件时,Html 页面窗体中 file 控件的 name 属性 **/ public String getParameterName() { return parameterName; } }
eclipse 回复于:2002-10-18 12:22:31
存放报文内容的类:
package mshtang.fileUpload; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import java.util.*;
/**存放报文内容的类,提供类似于 ServletRequest 中的部分 get 方法 *你必须在 html 页面的窗体(form)中指定 enctype="multipart/form-data"。 *才可以正确的使用这个类。 **/ public class ContentFactory { private Hashtable values; //存放name=value,其中value存放在另一个类中 private Hashtable files; //存放文件内容的。 private ContentFactory(Hashtable values, Hashtable files) { this.values=values; this.files=files; } public String getParameter(String name) { Vector v = (Vector)values.get(name); if( v != null) { return (String)v.elementAt(0); } return null; } public Enumeration getParameterNames() { return values.keys(); } public String[] getParameterValues(String name) { Vector v = (Vector)values.get(name); if(v != null) { String[] result = new String[v.size()]; v.toArray(result); return result; } return new String[0]; }
/** *返回一个 FileHolder 实例,该实例包含了通过字段名为name的file控件上载的文件信息, *如果不存在这个字段或者提交页面时,没有选择上载的文件,则返回 null。 * <p>;如果 Html 页面中存在不止一个字段名为name的file控件, * 返回值等于{@link #getFileParameterValues}中的第一个元素。 * * @param name:一个<code>;String</code>;,对应于Html页面窗体中file控件 *的name 属性。 * * @return返回:一个 FileHolder 实例,该实例包含了通过字段名为 name 的 file 控件上载的文件信息, *如果不存在这个字段或者提交页面是,没有选择上载的文件,则返回 null。 * * @see #getFileParameterValues * */ public FileHolder getFileParameter(String name) { Vector v = (Vector)files.get(name); if(v != null) { return (FileHolder)v.elementAt(0); } return null; } /** * 返回一个 由 String 对象构成的 Enumeration ,包含了 Html 页面 *窗体中所有 file 控件的 name 属性。 *如果窗体中没有 file 控件,则返回一个空的 Enumeration * @return 返回一个 由 String 对象构成的 Enumeration ,包含了 Html 页面 *窗体中所有 file 控件的 name 属性。 *如果窗体中没有 file 控件,则返回一个空的 Enumeration */ public Enumeration getFileParameterNames() { return files.keys(); } /** *返回一个 FileHolder 数组,该数组包含了所有通过字段名为 name 的 file 控件上载的文件信息, *如果不存在这个字段或者提交页面时,没有选择任何上载的文件,则返回一个 零元素的数组(不是 null )。 * @param name 一个 <code>;String</code>; ,对应于 Html 页面窗体中 file 控件 *的name 属性。 * * @return 返回一个 FileHolder 数组,该数组包含了所有通过字段名为 name 的 file 控件上载的文件信息, *如果不存在这个字段或者提交页面时,没有选择任何上载的文件,则返回一个 零元素的数组(不是 null )。 * * @see #getFileParameter */ public FileHolder[] getFileParameterValues(String name) { Vector v=(Vector)files.get(name); if(v!=null) { FileHolder[] result=new FileHolder[v.size()]; v.toArray(result); return result; } return new FileHolder[0]; } //------------->;Factory 部分 /** **返回根据当前请求生成的一个 ContentFactory 实例 **@param request 提交的请求 **@return 返回根据当前请求生成的一个 ContentFactory 实例,如果 request 数据包的内容不是以 mutilpart/form-data 型编码,则返回 null。 **@throws ContentFactoryException 当提交的数据和文件太大时抛出, **根据 Content-Length 判断,默认的许可值为 1024* 1024。 **/ public static ContentFactory getContentFactory(HttpServletRequest request) throws ContentFactoryException,IOException { // default maxLength is 1MB. return getContentFactory(request, 1024*1024); } /** **返回根据当前请求生成的一个 ContentFactory 实例 **@param request 提交的请求 **@param maxLength 数据包的最大长度,默认为1024*1024 **@return 返回根据当前请求生成的一个 ContentFactory 实例,如果 request 数据包的内容不是以 mutilpart/form-data 型编码,则返回 null。 **@throws ContentFactoryException 当提交的数据和文件太大时抛出, **根据 Content-Length 判断,默认的许可值为 1024* 1024。 **/ public static ContentFactory getContentFactory(HttpServletRequest request, int maxLength) throws ContentFactoryException, IOException { Hashtable values = new Hashtable(); Hashtable files = new Hashtable(); String contentType = request.getContentType(); int contentLength = request.getContentLength(); if (contentLength >; maxLength) { ContentFactoryException e=new ContentFactoryException("上传数据太多,请不要选择太大的文件"); throw e; } if(contentType == null || !contentType.startsWith("multipart/form-data")) { return null; } //get out the boudary from content-type int start = contentType.indexOf("boundary="); //这里应该 int boundaryLen = new String("boundary=").length(); String boundary = contentType.substring(start + boundaryLen); boundary = "--" + boundary; //用字节表示,以免 String 和 byte 数组的长度不一致 boundaryLen = bytesLen(boundary); //把request 中的数据读入一个byte数组 byte buffer[] = new byte[contentLength]; int once = 0; int total = 0; DataInputStream in = new DataInputStream(request.getInputStream()); while((total < contentLength) && (once >;= 0)) { once = in.read(buffer, total, contentLength); total += once; } //对buffer中的数据进行拆分 int pos1 = 0; //pos1 记录 在buffer 中下一个 boundary 的位置 //pos0,pos1 用于 subBytes 的两个参数 int pos0 = byteIndexOf(buffer, boundary, 0);//pos0 记录 boundary 的第一个字节在buffer 中的位置 do { pos0 += boundaryLen; //记录boundary后面第一个字节的下标 pos1 = byteIndexOf(buffer, boundary, pos0); if(pos1==-1) { break; }// pos0 += 2;//考虑到boundary后面的 \r\n parse(subBytes(buffer, pos0, pos1-2), values, files); //考虑到boundary后面的\r\n pos0=pos1; }while(true); return new ContentFactory(values,files); }
private static void parse(byte[] buffer, Hashtable values, Hashtable files) { /* this is a smiple to parse [boundary] Content-Disposition: form-data; name="file3"; filename="C:\Autoexec.bat" Content-Type: application/octet-stream
@echo off prompt $d $t [ $p ]$_$$
[boundary] Content-Disposition: form-data; name="Submit"
Submit [boundary] */ String[] tokens={"name=\"","\"; filename=\"", "\"\r\n","Content-Type: ","\r\n\r\n"}; // 0 1 2 3 4 int[] position=new int[tokens.length];
for (int i=0;i<tokens.length ;i++ ) { position=byteIndexOf(buffer,tokens,0); } if (position[1]>;0 && position[1]<position[2]) { //包含tokens 中的第二个元素,说明是个文件数据段 //1.得到字段名 String name =subBytesString(buffer,position[0]+bytesLen(tokens[0]),position[1]); //2.得到文件名 String file= subBytesString(buffer,position[1]+bytesLen(tokens[1]),position[2]); if (file.equals("")) return; file=new File(file).getName(); //this is the way to get the name from a path string //3.得到 Content-Type String contentType=subBytesString(buffer,position[3]+bytesLen(tokens[3]),position[4]); //4.得到文件内容 byte[] b=subBytes(buffer,position[4]+bytesLen(tokens[4]),buffer.length); FileHolder f=new FileHolder(b,contentType,file,name); Vector v=(Vector)files.get(name); if (v==null) { v=new Vector(); } if (!v.contains(f)) { v.add(f); } files.put(name,v); //同时将 name 属性和 file 属性作为普通字段,存入values; v=(Vector)values.get(name); if (v==null) { v=new Vector(); } if (!v.contains(file)) { v.add(file); } values.put(name,v); }else { // String[] tokens={"name=\"","\"; filename=\"", "\"\r\n","Content-Type: ","\r\n\r\n"} // index 0 1 2 3 4 //不包含tokens 中的第二个元素,说明是个 name/value 型的数据段 //所以没有tokens[1]和 tokens[3] //name 在 tokens[0] 和 tokens[2] 之间 //value 在 tokens[4]之后 //1.得到name String name =subBytesString(buffer,position[0]+bytesLen(tokens[0]),position[2]); String value= subBytesString(buffer,position[4]+bytesLen(tokens[4]),buffer.length); Vector v=(Vector)values.get(name); if (v==null) { v=new Vector(); } if (!v.contains(value)) { v.add(value); } values.put(name,v); } } /**字节数组中的 indexof 函数,与 String 类中的 indexOf类似 **@para source 源字节数组 **@para search 目标字符串 **@para start 搜索的起始点 **@return 如果找到,返回search的第一个字节在buffer中的下标,没有则返回-1 **/ private static int byteIndexOf (byte[] source,String search,int start) { return byteIndexOf(source,search.getBytes(),start); }
/**字节数组中的 indexof 函数,与 String 类中的 indexOf类似 **@para source 源字节数组 **@para search 目标字节数组 **@para start 搜索的起始点 **@return 如果找到,返回search的第一个字节在buffer中的下标,没有则返回-1 **/ private static int byteIndexOf (byte[] source,byte[] search,int start) { int i; if (search.length==0) { return 0; } int max=source.length-search.length; if (max<0) return -1; if (start>;max) return -1; if (start<0) start=0; // 在source中找到search的第一个元素 searchForFirst: for (i=start;i<=max ; i++) { if (source==search[0]) { //找到了search中的第一个元素后,比较剩余的部分是否相等 int k=1; while(k<search.length) { if (source[k+i]!=search[k]) { continue searchForFirst; } k++; } return i; } } return -1; } /** **用于从一个字节数组中提取一个字节数组 **类似于 String 类的substring() **/ private static byte[] subBytes(byte[] source,int from,int end) { byte[] result=new byte[end-from]; System.arraycopy(source,from,result,0,end-from); return result; } /** **用于从一个字节数组中提取一个字符串 **类似于 String 类的substring() **/ private static String subBytesString(byte[] source,int from,int end) { return new String(subBytes(source,from,end)); } /** **返回字符串S转换为字节数组后的长度 **/ private static int bytesLen(String s) { return s.getBytes().length; } }
huangmw 回复于:2002-10-18 16:13:53
好长的一篇代码,只有慢慢看了,不过还是谢谢
eclipse 回复于:2002-10-18 16:19:10
最后边两篇有兴趣了看,没兴趣了就不要看了,是我扩展的
三四五等几贴我想可以解决你的问题了,不过不是smart。
其实你可以将下载的smart反编译,看看具体代码,或者重新下载试试
huangmw 回复于:2002-10-18 16:26:19
呵呵,好的,谢谢,不过怎么反编译呢?啊。。。不要打我。。。菜鸟无罪
eclipse 回复于:2002-10-18 16:39:21
谈谈JAVA的反编译 谈谈JAVA的反编译 于瑶 如今JAVA语言在全世界范围正如火如荼般的流行,它广范地应用在INTERNET的数据库、多媒体、CGI、及动态网页的制作方面。1999年在美国对JAVA程序员的需求量首次超过C++! 作者因最近分析一些JAVA程序,对JAVA的反编译进行了一番了解,下面将我所了解的情况作以下介绍,希望对JAVA爱好者有所帮助。 JAVA是采用一种称做“字节编码”的程序结构,分为小程序(嵌入到HTML文件中)和应用程序(直接在命令状态下执行)两种类型。无论哪种结构,一旦用JAVAC 命令编译后,均变成后缀为CLASS的同名可执行文件。这种文件是不可阅读的代码。 经查阅了SUN公司的JDK(JDK1.1.3)文档资料后,我找到了一个据称是可反编译JAVA的JAVAP文件(EXE),这个文件位于\JDK\BIN\ 下面,经按说明使用后,感到失望,原来这个“反编译”仅可反编译出JAVA程序的数据区(定义)、若干方法和类的引用等。 这里我用了一个简单例子来说明问题。 JAVA的源程序hello_java.java如下:
import java.applet.*; import java.awt.*;
public class hello_java extends Applet { public void paint(Graphics g) { g.drawString("Hello Java!\n",20,20); } }
经用反编译命令:javap -c -package -public -private hello_java hello.java 得到的反编译结果(hello.java)如下:(有关javap命令的选择参数请见其使用说明,这里-c表示选择了反编译)
Compiled from hello_java.java public synchronized class hello_java extends java.applet.Applet /* ACC_SUPER bit set */ { public void paint(java.awt.Graphics); public hello_java();
Method void paint(java.awt.Graphics) 0 aload_1 1 ldc #1 <String "Hello Java! ">; 3 bipush 20 5 bipush 20 7 invokevirtual #6 <Method java.awt.Graphics.drawString(Ljava/lang/String;II)V>; 10 return
Method hello_java() 0 aload_0 1 invokespecial #5 <Method java.applet.Applet.<init>;()V>; 4 return }
从上述结果不难看出该反编译未能将源程序全译出来,像语句g.drawString("Hello Java!\n",20,20); 就没有。随着程序量增加,未能编译的JAVA语句还会更多。所以这个反编译程序仅能起个参考作用。 幸亏有了INTERNET,笔者通过YAHOO很快找到了一个JAVA反编译“自由软件”(SHAREWARE),http://www.inter.nl.net/users/H.P.van.Vliet/mocha.htm 。 这个软件叫MOCHA,据说是一位30来岁的加拿大的研究生所完成,仅是个“?”版,原因是这位叫做H.P.VAN.VLIET的小伙子患癌逝世了,十分可惜呀! 经使用MOCHA反编译软件,感到这个软件十分好用,笔者试反编译多个JAVA程序,均得到很好的结果。 这里给出如何使用这个软件,首先,用WINZIP等将"mocha-b1.zip" 解开得到"mocha.zip"文件,"mocha.zip"不须再解开,这个包内包括了反编译的类文件,只需将其拷贝到JDK所在的目录下,如:c:\jdk\bin\ 此外,须设置路径:SET CLASSPATH=c:\myclasses;c:\jdk\bin\mocha.zip MOCHA用法: java mocha.Decompiler [-v] [-o] Class1.class Class2.class ... "java" 调用Java虚拟机 "mocha.Decompiler" 指示要进行JAVA反编译 "-v" 选择详细输出 "-o" 选写入已有的.mocha 文件 "ClassX.class" 指出要反编译类名 注意,不需给出输出的JAVA文件名,因为MOCHA自动产生一个与CLASS同名但扩展名为MOCHA的JAVA源文件。 对于上例,可用命令: java mocha.Decompiler [-v] [-o] hello_java.class 得到的源文件: /* Decompiled by Mocha from hello_java.class */ /* Originally compiled from hello_java.java */
import java.applet.Applet; import java.awt.Graphics;
public synchronized class hello_java extends Applet { public void paint(Graphics g) { g.drawString("Hello Java!\n", 20, 20); }
public hello_java() { } } 我们不难发现,此文件与编译前的JAVA源文件完全一样!笔者曾经用MOCHA反编译出最大为80K的源文件,均取得成功。 在此,笔者向英年早逝的VLIET表示敬意,感谢他给我们留下这个工具软件。 如读者下载MOCHA有困难,可给笔者来电子邮件,笔者可将MOCHA寄去。
|
|