摘要:本文介紹了JavaBean實(shí)現(xiàn)多個(gè)文件上傳的兩種方法,分別是使用http協(xié)議和ftp協(xié)議實(shí)現(xiàn)。首先講述了http協(xié)議傳送多個(gè)文件的基本格式和實(shí)現(xiàn)上傳的詳細(xì)過(guò)程,之后簡(jiǎn)單介紹了使用ftpclient 類(lèi)實(shí)現(xiàn)了ftp方式的上傳,最后對(duì)這兩種方法進(jìn)行了比較。
關(guān)鍵字:JavaBean 、http 、ftp 、ftpclient
JavaBean是一種基于Java的軟件組件。JSP對(duì)于在Web 應(yīng)用中集成JavaBean組件提供了完善的支持。這種支持不僅能縮短開(kāi)發(fā)時(shí)間(可以直接利用經(jīng)測(cè)試和可信任的已有組件,避免了重復(fù)開(kāi)發(fā)),也為JSP應(yīng)用帶來(lái)了更多的可伸縮性。
文件的上傳功能在基于B/S的開(kāi)發(fā)模式中非常普遍。同其他開(kāi)發(fā)工具相比較,JSP對(duì)文件的上傳支持并不是很完美,它既不象ASP那樣一定需要使用組件來(lái)完成,也不像PHP那樣直接提供了文件上載的支持。JSP實(shí)現(xiàn)文件上傳的實(shí)現(xiàn)方式是這樣的:使用ServletRequest類(lèi)的getInputStream()方法獲得一個(gè)客戶(hù)端向服務(wù)器發(fā)出的數(shù)據(jù)流,然后處理這個(gè)數(shù)據(jù)流,從中分析、得到文件上傳中傳遞到服務(wù)器的各個(gè)參數(shù)和數(shù)據(jù),然后將其中的文件數(shù)據(jù)存儲(chǔ)為一個(gè)文件或插入到數(shù)據(jù)庫(kù)中。通常JSP頁(yè)面中不處理文件的上傳功能,而是把這些功能放到Servlet 或JavaBean中去實(shí)現(xiàn)。使用Servlet完成文件上傳的例子在一些JSP的相關(guān)書(shū)籍中都有所介紹,我這里介紹使用JeanBean是如何完成文件上傳的。JSP中實(shí)現(xiàn)文件的上傳可以采用兩種方式即采用HTTP協(xié)議和FTP協(xié)議實(shí)現(xiàn),二者在傳輸?shù)脑砩洗嬖诤艽蟮牟町?。以下將結(jié)合源代碼對(duì)它們的實(shí)現(xiàn)做簡(jiǎn)單介紹,相信讀者會(huì)從中有所收獲。以下程序已經(jīng)調(diào)試通過(guò)。調(diào)試的環(huán)境:window 2000 server+Apache +tomcat4.0,JavaBean調(diào)試環(huán)境:JDK1.4+Editplus。
在JSP中使用JavaBean實(shí)現(xiàn)基于Web的文件上傳功能一般需要三種文件結(jié)合完成。這三種文件分別是提供界面的HTML頁(yè)面文件、完成調(diào)用實(shí)現(xiàn)上傳功能的JavaBean的JSP文件和實(shí)現(xiàn)JavaBean的Java的類(lèi)文件。以下我將重點(diǎn)講述采用HTTP協(xié)議和FTP協(xié)議實(shí)現(xiàn)文件上傳功能的JavaBean部分。
1 采用HTTP協(xié)議實(shí)現(xiàn)多個(gè)文件的上傳
在過(guò)去的Html中,表單不能實(shí)現(xiàn)文件的上傳,這多少限制了一些網(wǎng)頁(yè)的功能。RFC1867規(guī)范(即Html中實(shí)現(xiàn)基于表單的文件上傳)對(duì)表單作出了擴(kuò)展,增加了一個(gè)表單元素〈input type=file>。通過(guò)使用這個(gè)元素,瀏覽器會(huì)自動(dòng)生成一個(gè)輸入框和一個(gè)按鈕,輸入框可供用戶(hù)填寫(xiě)本地的文件名和路徑名,按鈕可以讓瀏覽器打開(kāi)一個(gè)文件選擇框供用戶(hù)選擇文件。具體的表單實(shí)現(xiàn)如下:
FORMMETHOD="POST" ACTION="*.jsp" ENCTYPE="multipart/form-data">
INPUT TYPE="FILE" NAME="FILE1" SIZE="50">BR>
INPUT TYPE="SUBMIT" VALUE="Upload">
/FORM>
當(dāng)選擇了粘貼文件后就直接輸入本地文件的絕對(duì)路徑,表單的action屬性值是*.jsp,這意味著請(qǐng)求(包括上載的文件)將發(fā)送給*..jsp文件。在這個(gè)過(guò)程中實(shí)際上就實(shí)現(xiàn)了HTTP方式的文件上載。文件從客戶(hù)端到服務(wù)器的上載是由HTTP協(xié)議的通用網(wǎng)關(guān)界面(CGI)支持的。這種上載方式要求瀏覽器和WEBServer兩方面都能夠支持Rfc1867。JavaBean 通過(guò)ServletRequest類(lèi)的getInputStream()方法獲得一個(gè)客戶(hù)端向服務(wù)器發(fā)出的數(shù)據(jù)流、分析上傳的文件格式,根據(jù)分析結(jié)果將多個(gè)文件依次輸出服務(wù)器端的目標(biāo)文件中。本例中的JavaBeande的功能是由testUpload類(lèi)具體實(shí)現(xiàn)。TestUpload類(lèi)的框架如下:
public class testUpload
{
public testUpload(){……}
public final void initialize(ServletConfig config) throws ServletException
{ m_application = config.getServletContext(); }
public void upload() throws testUploadException, IOException, ServletException
{………}
private void getDataSection(){………}
private void getDataHeader(){………}
public int save (String destPathName)
throws SmartUploadException, IOException, ServletException
{………}
……
}
通過(guò)initialize()方法初始化Servlet的運(yùn)行環(huán)境。使用upload()方法獲得輸入流,并分析上傳文件的格式,并將各個(gè)上傳文件的屬性賦給多個(gè)File類(lèi)實(shí)例處理,這些File類(lèi)實(shí)例由Files類(lèi)管理。File類(lèi)根據(jù)各文件的屬性調(diào)用它的save ()方法將多個(gè)文件依次輸出服務(wù)器端的目標(biāo)文件中。其中upload()方法是關(guān)鍵,用于分析http1.1協(xié)議傳送文件的格式。經(jīng)過(guò)測(cè)試,我們得出傳輸流文件的格式,這對(duì)理解upload()方法很有用。例如,上傳我的文檔\tt.txt文件。格式如下:
//文件分隔符
-----------------------------7d226137250336
//文件信息頭
Content-Disposition: form-data; name="FILE1"; filename="C:\Documents and Settings\Administrator.TIMBER-4O6B0ZZ0\My Documents\tt.sql"
Content-Type: text/plain
//源文件內(nèi)容
create table info(
content image null);
//下一個(gè)文件的分隔符
-----------------------------7d226137250336
Content-Disposition: form-data; name="FILE2"; filename=""
Content-Type: application/octet-stream
-----------------------------7d226137250336
從以上文件我們可以看出,HTTP協(xié)議在上傳多個(gè)文件時(shí),是將文件全部放到輸入流并以一定的分隔符來(lái)區(qū)分的。實(shí)際上upload()方法就是要分析上面的文件,確定分隔符的內(nèi)容、各個(gè)文件的內(nèi)容格式、文件的完整路徑名稱(chēng)、及其文件的實(shí)際數(shù)據(jù)的始末位置。這里需要說(shuō)明的一點(diǎn)是分隔符是隨機(jī)的,它是傳輸流文件的第一個(gè)回車(chē)符之前的所有字符。
Upload()方法的實(shí)現(xiàn)流程是:首先將輸入流文件輸出到字節(jié)數(shù)組m_binArray中,通過(guò)下面的代碼實(shí)現(xiàn)。
m_totalBytes=1024;totalRead=0;
for(; totalRead m_totalBytes; totalRead += readBytes)
try
{ m_request.getInputStream();
readBytes = m_request.getInputStream().read(m_binArray, totalRead, m_totalBytes - totalRead);
}catch(Exception e){ throw new SmartUploadException("Unable to upload.");}
這里采用了循環(huán)中多字節(jié)讀取方法,以上循環(huán)不斷地讀取數(shù)據(jù)直到數(shù)組填滿(mǎn)為止。如果一個(gè)文件可以完全得到,則文件的所有字節(jié)也就可以全部得到。但是因?yàn)榫W(wǎng)絡(luò)速度通常比CPU慢得多,所以程序很容易在所有的數(shù)據(jù)到來(lái)之前就清空網(wǎng)絡(luò)緩沖區(qū)。實(shí)際上,多字節(jié)讀取方法在試圖從暫時(shí)為空但是開(kāi)放的網(wǎng)絡(luò)緩存區(qū)讀取數(shù)據(jù)時(shí),該方法會(huì)返回0,這表示沒(méi)有數(shù)據(jù)存在但網(wǎng)絡(luò)流沒(méi)有關(guān)閉。這種情況下,單字節(jié)方法將阻止運(yùn)行程序的執(zhí)行,所以多字節(jié)的行為優(yōu)于單字節(jié)read()方法的行為。接下來(lái)將分析字節(jié)數(shù)組m_binArray。首先找到分隔符;使用getDataHeader()方法返回文件信息頭的值,從中確定源文件的完整路徑名、源文件的擴(kuò)展名和源文件文件內(nèi)容格式;使用getDataSection()方法返回文件的內(nèi)容數(shù)據(jù),并記錄文件數(shù)據(jù)在字節(jié)數(shù)組中的起止位置。然后生成一個(gè)File類(lèi)實(shí)例,并將文件的完整路徑名、源文件的擴(kuò)展名、源文件文件內(nèi)容格式和文件的內(nèi)容數(shù)據(jù)的起止位置放到File類(lèi)實(shí)例的屬性中。找到下一個(gè)分隔符,繼續(xù)重復(fù)上述過(guò)程,直至分析完畢。
2 采用FTP協(xié)議實(shí)現(xiàn)多個(gè)文件的上傳
FTP協(xié)議是Internet上用來(lái)傳送文件的協(xié)議,規(guī)定了Internet上文件互相傳送的標(biāo)準(zhǔn)。在java中實(shí)現(xiàn)這一功能是借助FtpClient類(lèi)完成的。具體實(shí)現(xiàn)過(guò)程:首先與FTP服務(wù)器建立連接;初始化文件的傳輸方式,包括ASCII和BINARY兩種方式;將文件輸出到文件輸入流FileInputStream中;FileInputStream中的數(shù)據(jù)讀入字節(jié)數(shù)組中;字節(jié)數(shù)組中的數(shù)據(jù)寫(xiě)入輸出流TelnetOutputStream(利用write方法將數(shù)據(jù)寫(xiě)入到一個(gè)網(wǎng)絡(luò)鏈接上)。這樣和源文件同名的一個(gè)文件就復(fù)制到了服務(wù)器端。本例的JavaBean中通過(guò)connectServer()、upload()和closeConnect()三個(gè)方法完成文件上傳過(guò)程。主要實(shí)現(xiàn)如下:
public class ftpUpload
{ String filename;String filename1;FtpClient ftpClient;
public void connectServer(string server,string user,string password,string path)
{
//server:FTP服務(wù)器的IP地址;user:登錄FTP服務(wù)器的用戶(hù)名
//password:登錄FTP服務(wù)器的用戶(hù)名的口令;path:FTP服務(wù)器上的路徑
try{ ftpClient=new FtpClient();
ftpClient.openServer(server);
ftpClient.login(user, password);
System.out.println("login success!");
if (path.length()!=0) ftpClient.cd(path);
ftpClient.binary(); }catch (IOException ex) {System.out.println(ex);}
}
public void closeConnect()
{try{ ftpClient.closeServer();
}catch (IOException ex) {System.out.println(ex);}
}
public void upload()
{ filename1=findFileName(filename);
//從filename中分析出文件的名稱(chēng),作為目標(biāo)文件的名稱(chēng),具體方法實(shí)現(xiàn)未給出
try {
TelnetOutputStream os=ftpClient.put(filename1);
java.io.File file_in=new java.io.File(filename);
FileInputStream is=new FileInputStream(file_in);
byte[] bytes=new byte[1024];
int c;
while ((c=is.read(bytes))!=-1){ os.write(bytes,0,c); }
is.close(); os.close();
} catch (IOException ex) {System.out.println(ex);}
}
}
connectServer()完成與FTP服務(wù)器建立連接的功能,使用FtpClient的openServer(string server)方法打開(kāi)遠(yuǎn)程FTP服務(wù)器,然后使用FtpClient的login(user, password)方法登錄服務(wù)器。登錄遠(yuǎn)程FTP服務(wù)器有兩種方式,一種是注冊(cè)用戶(hù)登錄,另一種是以匿名方式登錄。前者要求用戶(hù)首先注冊(cè)為服務(wù)器的客戶(hù),服務(wù)器會(huì)給客戶(hù)一個(gè)登錄賬號(hào)和密碼,依據(jù)賬號(hào)和密碼連結(jié)到服務(wù)器上。后者要求用戶(hù)不用注冊(cè)而使用特殊的用戶(hù)名"annoymous"和"guest"有限制的訪問(wèn)遠(yuǎn)程主機(jī)的公開(kāi)文件,現(xiàn)在許多系統(tǒng)要求用戶(hù)將Email地址作為口令。出于安全的目的,大部分匿名FTP主機(jī)一般只允許遠(yuǎn)程用戶(hù)下載文件,而不允許上傳,這將依賴(lài)于FTP服務(wù)器的設(shè)置。用戶(hù)可根據(jù)實(shí)際情況選擇使用兩種方式。登錄完成后使用FtpClient的binary()方法初始化傳輸方式為字節(jié)方式。upload()完成文件的上傳功能。創(chuàng)建源文件的文件輸入流FileInputStream,將輸入流寫(xiě)入到字節(jié)數(shù)組中,利用TelnetOutputStream的write方法將字節(jié)數(shù)組中的數(shù)據(jù)寫(xiě)入到一個(gè)網(wǎng)絡(luò)鏈接上。由于TelnetOutputStream打開(kāi)的是FTP服務(wù)器上的一個(gè)文件,所以數(shù)據(jù)寫(xiě)入到了目標(biāo)文件中,這樣就完成了文件上傳。closeConnect()要求與服務(wù)器斷開(kāi)連接。
以上只是單個(gè)文件上傳的過(guò)程,如果是多個(gè)文件可以多次調(diào)用此上傳過(guò)程。由以上兩種方式我們可以看出采用FTP協(xié)議實(shí)現(xiàn)多個(gè)文件的上傳比較簡(jiǎn)單,容易實(shí)現(xiàn)。利用FTP協(xié)議上傳文件一般是編寫(xiě)的客戶(hù)端的程序,服務(wù)器端的安全設(shè)置會(huì)比較復(fù)雜;而利用HTTP協(xié)議上傳文件則是服務(wù)器端的應(yīng)用程序,相對(duì)來(lái)說(shuō)安全設(shè)置會(huì)比較簡(jiǎn)單。并且通過(guò)測(cè)試發(fā)現(xiàn)FTP上傳方式在傳輸大文件時(shí)速度是HTTP上傳方式的幾十倍甚至幾百倍,但在傳輸小于1M的文件時(shí)卻比HTTP上傳方式稍慢一些。所以說(shuō)兩種傳輸方式各有優(yōu)勢(shì),請(qǐng)讀者根據(jù)自身情況量力而行。如果有什么問(wèn)題或者是需要其他部分的源碼,請(qǐng)與我聯(lián)系!
您可能感興趣的文章:- java Springboot實(shí)現(xiàn)多文件上傳功能
- JavaWeb實(shí)現(xiàn)多文件上傳及zip打包下載
- java實(shí)現(xiàn)多文件上傳至本地服務(wù)器功能
- Java Web使用Html5 FormData實(shí)現(xiàn)多文件上傳功能
- uploadify java實(shí)現(xiàn)多文件上傳和預(yù)覽
- Java中多媒體文件上傳及頁(yè)面回顯的操作代碼
- java 文件上傳(單文件與多文件)
- java文件上傳(單文件 多文件)與刪除
- Java實(shí)現(xiàn)ftp文件上傳下載解決慢中文亂碼多個(gè)文件下載等問(wèn)題
- Java實(shí)現(xiàn)多文件上傳功能