一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - Java實現FTP批量大文件上傳下載篇1

Java實現FTP批量大文件上傳下載篇1

2020-06-08 12:10ycb1689 JAVA教程

這篇文章主要為大家詳細介紹了Java實現FTP批量大文件上傳下載的基礎篇,具有一定的參考價值,感興趣的小伙伴們可以參考一下

本文介紹了在Java中,如何使用Java現有的可用的庫來編寫FTP客戶端代碼,并開發成Applet控件,做成基于Web的批量、大文件的上傳下載控件。文章在比較了一系列FTP客戶庫的基礎上,就其中一個比較通用且功能較強的j-ftp類庫,對一些比較常見的功能如進度條、斷點續傳、內外網的映射、在Applet中回調JavaScript函數等問題進行詳細的闡述及代碼實現,希望通過此文起到一個拋磚引玉的作用。

一、引子

筆者在實施一個項目過程中出現了一種基于Web的文件上傳下載需求。在全省(或全國)各地的用戶,需要將一些文件上傳至某中心的文件服務器上。這些文件是用于一些大型的工程建設,可能涉及到上千萬甚至上億的建設工程。文件具有三個鮮明的特征:一是文件大,可能達到50M;二是文件數量多,有可能15個左右;三是數據安全性方面要求數字簽名及數據加密。 

首先考慮到是基于HTTP的傳輸方式。但筆者通過比較很快發現滿足上面的需求: 

1:用HTTP協議上傳,似乎更適合web編程的方便性;上傳小于1M文件速度要比用FTP協議上傳文件略快。但對于批量及大文件的傳輸可能無能為力。當然,它也有它的優勢,如不像FTP那樣,必須在服務器端啟動一個FTP服務。 

2:用FTP協議上傳文件大于1M的文件速度比HTTP快。文件越大,上傳的速度就比HTTP上傳的速度快數倍。而且用java編寫程序;FTP比HTTP方便。 

筆者曾經使用VB也寫過ActiveX控件來進行批量文件的上傳下載,其功能也很強大。只是由于沒有對CAB文件或OCX進行專門的數字簽名,因此需要進行客戶端煩瑣的設置,如設置安全站點、降低客戶端的安全級別等等,因而放棄了些方案。 

同時考慮到在需在客戶端對文件進行數字簽名及數據加密,決定采用Applet的方式實現。。文件上傳之前,在客戶端可以獲取本地USBKEY密鑰信息,完成對上傳文件的加密和簽名處理。雖然采用Applet要求在客戶端安裝JRE運行時環境,給客戶端的管理及使用帶來一度的不方便性,但是相對起如此大量的文件及文件的安全性,這也許已經算是比較小的代價了。 

總結一下運行的環境為:

FTP服務器端:Serv-U,專業的FTP服務器端程序,網上有現成的軟件下載,當然讀者也可能自己寫一個服務器端的FTP文件接收程序來進行解釋。如果沒有特殊要求或功能的話,Serv-U應該可以滿足我們一般上傳下載的需求了; 

客戶端:Java applet,當年讓Java大火了一把的號稱與微軟的ActiveX相提并論的技術當然,現在Java出了JavaFX,是不是Applet的替代品呢? 

應用環境:Internet網,最終目的。 

二、Java FTP客戶端庫的選擇 

讓我們設想這樣一個情形--我們想寫一個純Java的從一個遠程計算機上運行的FTP服務器上傳下載文件的應用程序;我們還希望能夠得到那些供下載的遠程文件的基本文件信息,如文件名、數據或者文件大小等。 

盡管從頭開始寫一個FTP協議處理程序是可能的,并且也許很有趣,但這項工作也是困難、漫長并且存在著潛在的危險。因為我們不愿意親自花時間、精力、或者金錢去寫這樣的一個處理程序,所以我們轉而采用那些已經存在的可重用的組件。并且很多的庫存在于網上。 

找一個優秀的適合我們需要的Java FTP 客戶端庫并不像看起來那么簡單。相反這是一項非常痛苦復雜的工作。首先找到一個FTP客戶端庫需要一些時間,其次,在我們找到所有的存在的庫后,我們該選哪一個呢?每個庫都適合不同的需求。這些庫在性能上是不等價的,并且它們的設計上有著根本上的差別。每個類庫都各具特點并使用不同的術語來描述它們。因而,評價和比較FTP客戶端庫是一件困難的事情。 

使用可重用組件是一種值得提倡的方法,但是在這種情況下,剛開始往往是令人氣餒的。后來或許有點慚愧:在選擇了一個好的FTP庫后,其后的工作就非常簡單了,按簡單的規則來就行了。目前,已經有很多公開免費的ftp客戶端類庫,如simpleftp、J-ftp等,還有很多其他的ftpclient。如下表所示,表中未能全部列出,如讀者有更好的客戶端FTP類庫,請進行進一步的補充。

Java實現FTP批量大文件上傳下載篇1

在本文中,筆者采用是J-ftp。這個是個開源的且功能十分強大的客戶端FTP類庫。筆者很喜歡,同時也向各位讀者推薦一下。算了免費為它做一個廣告。

三、基本功能

 1、 登陸 
采用FTP進行文件傳輸,其實本質上還是采用Java.net.socket進行通信。以下代碼只是類net.sf.jftp.net.FtpConnection其中一個login方法。當然在下面的代碼,為了節省版面,以及將一些原理闡述清楚,筆者將一些沒必要的代碼去掉了,如日志等代碼。完整的代碼請參考J-ftp的源代碼或是筆者所以的示例源代碼,后面的代碼示例也同理:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
public int login(String username, String password)
{
 this.username = username;
 this.password = password;
 
 int status = LOGIN_OK;
 
 jcon = new JConnection(host, port);
 
 if(jcon.isThere())
 {
  in = jcon.getReader();
 
  if(getLine(POSITIVE) == null)//FTP220_SERVICE_READY) == null)
  {
   ok = false;   
   status = OFFLINE;
  }
 
  if(!getLine(loginAck).startsWith(POSITIVE))//FTP230_LOGGED_IN))
  {   
   if(success(POSITIVE))//FTP230_LOGGED_IN))
   {    
   }
   else
   {
    ok = false;
    status = WRONG_LOGIN_DATA;
   }
  }
 }
 else
 {
  if(msg)
  {
   Log.debug("FTP not available!");
   ok = false;
   status = GENERIC_FAILED;
  }
 }
 
 if(ok)
 {
  connected = true;
  system();
  binary();
  
  String[] advSettings = new String[6];
 
  if(getOsType().indexOf("OS/2") >= 0)
  {
   LIST_DEFAULT = "LIST";
  }
 
  if(LIST.equals("default"))
  {
   //just get the first item (somehow it knows first is the
   //FTP list command)
   advSettings = LoadSet.loadSet(Settings.adv_settings);
 
   //*** IF FILE NOT FOUND, CREATE IT AND SET IT TO LIST_DEFAULT
   if(advSettings == null)
   {
    LIST = LIST_DEFAULT;
 
    SaveSet s = new SaveSet(Settings.adv_settings, LIST);
   }
   else
   {
    LIST = advSettings[0];
 
    if(LIST == null)
    {
     LIST = LIST_DEFAULT;
    }
   }
  }
 
  if(getOsType().indexOf("MVS") >= 0)
  {
   LIST = "LIST";
  }
 
  //***
  fireDirectoryUpdate(this);
  fireConnectionInitialized(this);
 }
 else
 {
  fireConnectionFailed(this, new Integer(status).toString());
 }
 
 return status;
}

此登陸方法中,有一個JConnection類,此類負責建立socket套接字    ,同時,此類是一種單獨的線程,這樣的好處是為了配合界面的變化,而將網絡的套接字連接等工作做為單獨的線程來處理,有利于界面的友好性。下面是net.sf.jftp.net.JConnection類的run方法,當然,此線程的啟動是在JConnection類的構造方法中啟動的。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public void run()
{
 try
 {
  s = new Socket(host, port);
 
  localPort = s.getLocalPort();
 
  //if(time > 0) s.setSoTimeout(time);
  out = new PrintStream(new BufferedOutputStream(s.getOutputStream(),
              Settings.bufferSize));
  in = new BufferedReader(new InputStreamReader(s.getInputStream()),
        Settings.bufferSize);
  isOk = true;
 
  // }
 }
 catch(Exception ex)
 {
  ex.printStackTrace();
  Log.out("WARNING: connection closed due to exception (" + host +
    ":" + port + ")");
  isOk = false;
 
  try
  {
   if((s != null) && !s.isClosed())
   {
    s.close();
   }
 
   if(out != null)
   {
    out.close();
   }
 
   if(in != null)
   {
    in.close();
   }
  }
  catch(Exception ex2)
  {
   ex2.printStackTrace();
   Log.out("WARNING: got more errors trying to close socket and streams");
  }
 }
 
 established = true;
}

此run方法中的socket這里說明一下,此類實現客戶端套接字(也可以就叫“套接字”),套接字是兩臺機器之間的通信端點。套接字的實際工作由 SocketImpl 類的實例執行。應用程序通過更改創建套接字實現的套接字工廠可以配置它自身,以創建適合本地防火墻的套接字。具體的說明請參考JDK5 的API說明,最好是中文的。呵呵。 

2 上傳下載
 文件的上傳可以分成多線程及單線程,在單線程情況下比較簡單,而在多線程的情況下,要處理的事情要多點,同時也要小心很多。下面是net.sf.jftp.net.FtpConnection的上傳handleUpload方法。已經考慮了單線程及多線程兩種不同的類型。 

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public int handleUpload(String file, String realName)
 {
  if(Settings.getEnableMultiThreading() &&
    (!Settings.getNoUploadMultiThreading()))
  {
   Log.out("spawning new thread for this upload.");
 
   FtpTransfer t;
 
   if(realName != null)
   {
    t = new FtpTransfer(host, port, getLocalPath(), getCachedPWD(),
         file, username, password, Transfer.UPLOAD,
         handler, listeners, realName, crlf);
   }
   else
   {
    t = new FtpTransfer(host, port, getLocalPath(), getCachedPWD(),
         file, username, password, Transfer.UPLOAD,
         handler, listeners, crlf);
   }
 
   lastTransfer = t;
 
   return NEW_TRANSFER_SPAWNED;
  }
  else
  {
   if(Settings.getNoUploadMultiThreading())
   {
    Log.out("upload multithreading is disabled.");
   }
   else
   {
    Log.out("multithreading is completely disabled.");
   }
 
   return (realName == null) ? upload(file) : upload(file, realName);
  }
}

在多線程的情況下,有一個單獨的類net.sf.jftp.net .FtpTransfer,當然,多線程情況下,此類肯定是一個單獨的線程了。與JConnection相似,其線程的啟動也是在構造方法中啟動。而在它的run方法中,進行文件的讀取及傳輸。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
public void run()
{
 if(handler.getConnections().get(file) == null)
 {
  handler.addConnection(file, this);
 }
 else if(!pause)
 {
  Log.debug("Transfer already in progress: " + file);
  work = false;
  stat = 2;
 
  return;
 }
 
 boolean hasPaused = false;
 
 while(pause)
 {
  try
  {
   runner.sleep(100);
 
   if(listeners != null)
   {
    for(int i = 0; i < listeners.size(); i++)
    {
     ((ConnectionListener) listeners.elementAt(i)).updateProgress(file,
                     PAUSED,
                     -1);
    }
   }
 
   if(!work)
   {
    if(listeners != null)
    {
     for(int i = 0; i < listeners.size(); i++)
     {
      ((ConnectionListener) listeners.elementAt(i)).updateProgress(file,
                      REMOVED,
                      -1);
     }
    }
   }
  }
  catch(Exception ex)
  {
  }
 
  hasPaused = true;
 }
 
 while((handler.getConnectionSize() >= Settings.getMaxConnections()) &&
    (handler.getConnectionSize() > 0) && work)
 {
  try
  {
   stat = 4;
   runner.sleep(400);
 
   if(!hasPaused && (listeners != null))
   {
    for(int i = 0; i < listeners.size(); i++)
    {
     ((ConnectionListener) listeners.elementAt(i)).updateProgress(file,
                     QUEUED,
                     -1);
    }
   }
   else
   {
    break;
   }
  }
  catch(Exception ex)
  {
   ex.printStackTrace();
  }
 }
 
 if(!work)
 {
  if(listeners != null)
  {
   for(int i = 0; i < listeners.size(); i++)
   {
    ((ConnectionListener) listeners.elementAt(i)).updateProgress(file,
                    REMOVED,
                    -1);
   }
  }
 
  handler.removeConnection(file);
  stat = 3;
 
  return;
 }
 
 started = true;
 
 try
 {
  runner.sleep(Settings.ftpTransferThreadPause);
 }
 catch(Exception ex)
 {
 }
 
 con = new FtpConnection(host, port, remotePath, crlf);
 
 con.setConnectionHandler(handler);
 con.setConnectionListeners(listeners);
 
 int status = con.login(user, pass);
 
 if(status == FtpConnection.LOGIN_OK)
 {
  File f = new File(localPath);
  con.setLocalPath(f.getAbsolutePath());
 
  if(type.equals(UPLOAD))
  {
   if(newName != null)
   {
    transferStatus = con.upload(file, newName);
   }
   else
   {
    transferStatus = con.upload(file);
   }
  }
  else
  {
   transferStatus = con.download(file,this.newName);
  }
 }
 
 if(!pause)
 {
  handler.removeConnection(file);
 }
}

 至于下載的過程,因為它是上傳的逆過程,與上傳的方法及寫法大同小異,在些出于篇幅的考慮,并沒有將代碼列出,但其思想及思路完全一樣。請讀者參考源代碼。

四、 進度條

可以想象,如果在上傳或是下載的過程中,沒有任何的提示,用戶根本沒法判斷任務是否完成或是任務是否死了,常常由于上傳時間或下載時間過長而誤導用戶。因此,進度條就顯得非常的重要與實用。 

進度條的實現,其實說起來很簡單。就是在程序中開啟兩個線程,第一個線程用于動態的改變界面上進度條的value值,而第二個線程則在上傳或是下載的過程中,做成一個循環,在此循環中,每次讀取一定數量如8192字節數的數據。然后傳完此數據后,調用第一個線程中的updateProgress方法,來更新界面進度條的value值。 

而上傳或下載的過程中(見上一節的FtpTransfer類的run方法),可以查看,con.upload(file, newName)方法,代碼如下所示,

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public int upload(String file, String realName, InputStream in)
{
 hasUploaded = true;
 Log.out("ftp upload started: " + this);
 
 int stat;
 
 if((in == null) && new File(file).isDirectory())
 {
  shortProgress = true;
  fileCount = 0;
  baseFile = file;
  dataType = DataConnection.PUTDIR;
  isDirUpload = true;
 
  stat = uploadDir(file);
 
  shortProgress = false;
 
  //System.out.println(fileCount + ":" + baseFile);
  fireProgressUpdate(baseFile,
       DataConnection.DFINISHED + ":" + fileCount, -1);
 
  fireActionFinished(this);
  fireDirectoryUpdate(this);
 }
 else
 {
  dataType = DataConnection.PUT;
  stat = rawUpload(file, realName, in);
 
  try
  {
   Thread.sleep(100);
  }
  catch(Exception ex)
  {
  }
 
  fireActionFinished(this);
  fireDirectoryUpdate(this);
 }
 
 try
 {
  Thread.sleep(500);
 }
 catch(Exception ex)
 {
 }
 
 return stat;
}

此方法進行負責上傳一定字節數量的內容,其實就是調用rawUpload方法,這里沒列出,請參考源代碼,而當傳完此字節數據后,通過調用fireActionFinished()方法來調用主線程中的updateProgressBar()方法。其實代碼如下: 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
protected void updateProgressBar() {
 int percent = (int) (((float) lFileCompleteSize / (float) lFileSize) * 10000F);
 pbFile.setValue(percent);
 // System.out.println("================================================="+percent);
 pbFile.setString(lFileCompleteSize / 1024L + "/" + lFileSize / 1024L
   + " kB");
 percent = (int) (((float) lTotalCompleteSize / (float) lTotalSize) * 10000F);
 pbTotal.setString(lTotalCompleteSize / 1024L + "/" + lTotalSize / 1024L
   + " kB");
 pbTotal.setValue(percent);
 repaint();
}

上面用了兩個進度條,第一個進度條表示當前文件的上傳或下載進度,第二個進度條表示所有文件下載或上傳的進度。同時,為了產生進度條的移動或變化進度幅度比較明顯,通過pbFile.setMaximum(10000)及pbTotal.setMaximum(10000)將進度條的最大值設置成10000,而不是平時我們所設置的100。筆者認為這樣比較好看,因為有的時候上傳或下載的時候由于網絡原因,可能變化比較小。若設置成100則變化不是特別明顯。

以上就是FTP批量大文件上傳下載的基礎篇,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 亚洲视频在线一区二区三区 | sss亚洲国产欧美一区二区 | 91麻豆精品国产自产在线观看 | 91国内精品久久久久怡红院 | www.色呦呦.com| 国产欧美曰韩一区二区三区 | 亚洲午夜精品久久久久久成年 | 精品欧美一区二区三区四区 | 亚洲视频免费在线观看 | freefron性中国国产高清 | 嗯啊好大视频 | 日本在线精品视频 | 极品丝袜小说全集 | 男男gaygays黑人 | 91香蕉国产视频 | 免费国产高清精品一区在线 | 乳色吐息讲的是什么 | 国产精品合集一区二区 | 色噜噜国产精品视频一区二区 | 日本成熟 | 国产精品va在线观看手机版 | a级毛片毛片免费很很综合 a级黄色视屏 | 国产精品密播放国产免费看 | 色愉拍亚洲偷自拍 | 四虎精品成人a在线观看 | 国产盗摄美女嘘嘘视频 | 国产精品理论片在线观看 | 女老板用丝袜脚夹我好爽 | 亚洲欧洲色图 | 美人老师沦为 | 好大好硬好深好爽想要小雪 | 国产一级在线免费观看 | 亚洲天堂v | 特黄特色大片免费视频播放 | 免费观看毛片视频 | 国产麻豆视频 | 99这里只有精品视频 | 好男人好资源在线观看免费 | 国产欧美日韩不卡 | 成人观看免费大片在线观看 | 免费观看视频高清在线 |