我下載了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寄去。
|
|