Java 輕量級呼叫 FTP 上傳(安卓可用)
Edit:6-19,獨立一個標準 Java 專案了,
Edit:5-13 更新:為避免與原有 rt.jar 衝突,特意把 sun.* 包名修改,參見在這裡的原始碼。
今時今日 HTTP 斷點上傳、WebSocket 斷點上傳興起,FTP 協議大有被取代之勢,不過 FTP 顧名思義,始終是為檔案傳輸所服務的,擁有 HTTP 協議所不具備的優勢:首先是適合大檔案上傳、多批次上傳,一般 10MB 甚至上 G 的檔案亦可,而且進度條、斷點、多執行緒上傳等功能一應俱全;其次開發維護方便,——服務端可以用現成的方案,例如經典的 IIS FTP、ServU 等,或者寫一個伺服器端的 FTP 檔案接收程式來進行解釋,但這樣的輪子已經很多了,比如最近的關注 nodejs 也有開源的 FTP 服務方案,所以服務端推薦現成的即可,而且還有一點就是,服務端一般無需開發編碼而是直接使用,進行相關設定引數即可;客戶端 app 的方案,更是有很多選擇。姑且不說 Java 領域裡面一大堆開源 FTP 專案,其實 Java 類庫自帶就有 FTP 客戶端,只不過並非作為標準庫出現,而且蘊含在 rt.jar 的 sun.net.* 下面;最後我想到 FTP 的優點是自帶賬號系統,甚至可以對許可權進行細分。
筆者最開始使用的是 org.apache.commons.net.ftp.* 包,但相關的例子卻找不到上傳進度的,而且聽說“用 FTPClient(apache)想要強行加入上傳檔案的速度檢測比較麻煩”。令我沮喪,於是唯有試試其他方案。發現 Java 開源世界仍舊精彩,各種 FTP Client 比比皆是:
這麼多怎麼選擇呢?如果是一般簡單的上傳下載,犯不著引入臃腫第三方庫,使用 Sun 出品的 sun.net.ftp.FtpClient 即可滿足。筆者試過 FtpClient 後,可以加入獲取進度的功能,於是就可以拋棄 200多 kb 的 Apache FTP 包啦。——然而遺憾的是,在安卓專案中,Sun FTP 卻無法順利使用。
怎麼說?蓋因安卓的 JDK 自行體系,是沒有加入 rt.jar 這樣非標準庫的包(而 Web 環境則無壓力)。我百度了一下,雖然可以提供部分 FtpClient 原始碼但不是完整的。好在 Java 就是開源的,——轉戰谷歌搜尋立馬就搜到 JDK 的完整程式碼。開始的時候是 CSDN 下載的,不過夠奇葩的是,
想想 Java 布林型別可以用 0/1 表示那是多的老版本呀,故所以接著各種報錯就在所難免。
於是再找新版本的的 JDK,——OpenJDK 1.7,這下可以有了,最新原始碼,註釋也有,可是就是進化得“太先進”了,包分的太細,依賴 N 個類,抽出來太費力了。怎麼辦?退而求其次,來個 1.6 看怎麼樣,果然 1.6 的符合剛好夠用的原則,主要是以下幾個類。
下面是相關 API 說明。
sun.net.ftp.FtpClient 該類庫主要提供了用於建立 FTP 連線的類。利用這些類的方法,程式設計人員可以遠端登入到 FTP 伺服器,列舉該伺服器上的目錄,設定傳輸協議,以及傳送檔案。FtpClient 類涵蓋了幾乎所有FTP的功能,FtpClient 的例項變數儲存了有關建立"代理"的各種資訊。
public static boolean useFtpProxy
這個變數用於表明FTP傳輸過程中是否使用了一個代理,因此,它實際上是一個標記,此標記若為 TRUE,表明使用了一個代理主機。public static String ftpProxyHost 此變數只有在變數 useFtpProxy 為 TRUE 時才有效,用於儲存代理主機名。
public static int ftpProxyPort 此變數只有在變數useFtpProxy為TRUE時才有效,用於儲存代理主機的埠地址。
FtpClient有三種不同形式的建構函式,如下所示:
1、public FtpClient(String hostname,int port) 此建構函式利用給出的主機名和埠號建立一條FTP連線。
2、public FtpClient(String hostname)
此建構函式利用給出的主機名建立一條FTP連線,使用預設埠號。3、FtpClient()
此建構函式將建立一FtpClient類,但不建立FTP連線。這時,FTP連線可以用openServer方法建立。一旦建立了類FtpClient,就可以用這個類的方法來開啟與FTP伺服器的連線。類ftpClient提供瞭如下兩個可用於開啟與FTP伺服器之間的連線的方法。
public void openServer(String hostname)
這個方法用於建立一條與指定主機上的FTP伺服器的連線,使用預設埠號。public void openServer(String host,int port)
這個方法用於建立一條與指定主機、指定埠上的FTP伺服器的連線。開啟連線之後,接下來的工作是註冊到FTP伺服器。這時需要利用下面的方法。
public void login(String username,String password)
此方法利用引數username和password登入到FTP伺服器。使用過Intemet的使用者應該知道,匿名FTP伺服器的登入使用者名稱為anonymous,密碼一般用自己的電子郵件地址。下面是FtpClient類所提供的一些控制命令。
public void cd(String remoteDirectory):該命令用於把遠端系統上的目錄切換到引數remoteDirectory所指定的目錄。
public void cdUp():該命令用於把遠端系統上的目錄切換到上一級目錄。
public String pwd():該命令可顯示遠端系統上的目錄狀態。
public void binary():該命令可把傳輸格式設定為二進位制格式。
public void ascii():該命令可把傳輸協議設定為ASCII碼格式。
public void rename(String string,String string1):該命令可對遠端系統上的目錄或者檔案進行重新命名操作。除了上述方法外,類FtpClient還提供了可用於傳遞並檢索目錄清單和檔案的若干方法。這些方法返回的是可供讀或寫的輸入、輸出流。下面是其中一些主要的方法。
public TelnetInputStream list()
返回與遠端機器上當前目錄相對應的輸入流。public TelnetInputStream get(String filename)
獲取遠端機器上的檔案filename,藉助TelnetInputStream把該檔案傳送到本地。public TelnetOutputStream put(String filename)
以寫方式開啟一輸出流,通過這一輸出流把檔案filename傳送到遠端計算機。
至此,我們已經把 sun.net.ftp 的包單獨抽取出來,安卓也可用使用了。
下面是呼叫的例子,主要是 UploadFtp 工具類,繼承 FtpClient。UploadProgressListener 是上傳進度條控制器,你可以修改其中的 update() 通知 UI 更新進度條。
package ftp;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import sun.net.TelnetInputStream;
import sun.net.TelnetOutputStream;
import sun.net.ftp.FtpClient2;
public class UploadFtp extends FtpClient2 {
public UploadFtp(String server, int port) throws IOException {
super(server, port);
}
/**
* 用書上傳本地檔案到ftp伺服器上
*
* @param source
* 上傳檔案的本地路徑
* @param target
* 上傳到ftp的檔案路徑
* @return
*/
public void upload(String source, String target) {
TelnetOutputStream ftp = null;
InputStream file = null;
try {
binary();
ftp = put(target);
file = new FileInputStream(new File(source));
BufferedInputStream in = new BufferedInputStream(file);
new ProgressListener().copy(in, new BufferedOutputStream(ftp), in.available());
System.out.print("put file suc from " + source + " to " + target + "\r\n");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(ftp != null)ftp.close();
if(file != null)file.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 從ftp上下載所需要的檔案
*
* @param source
* 在ftp上路徑及檔名
* @param target
* 要儲存的本地的路徑
* @return
*/
public void getFile(String source, String target) {
TelnetInputStream ftp = null;
OutputStream file = null;
try {
binary();
ftp = get(source);
file = new FileOutputStream(new File(target));
ProgressListener listener = new ProgressListener();
listener.setFileName(target);
listener.copy(
new BufferedInputStream(ftp),
new BufferedOutputStream(file),
getFileSize(source, ftp)
);
System.out.print("get file suc from " + source + " to " + target + "\r\n");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(ftp != null)ftp.close();
if(file != null)file.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 為了計算下載速度和百分比,讀取ftp該檔案的大小
*
* @param source
* @param ftp
* @return
* @throws IOException
*/
private int getFileSize(String source, TelnetInputStream ftp) throws IOException {
// 這裡的組合使用是必須得 sendServer 後到 readServerResponse
sendServer("SIZE " + source + "\r\n");
if (readServerResponse() == 213) {
String msg = getResponseString();
try {
return Integer.parseInt(msg.substring(3).trim());
} catch (Exception e) {}
}
return 0;
}
public static void main(String[] args) {
UploadFtp client;
try {
client = new UploadFtp("192.168.61.83", 21);
client.login("upup", "[email protected]");
// client.PutFile("D:\\code.jar", "/test/1344439.jar");
client.upload("E:\\aa.mp4", "/temp/zzz.mp4");
client.closeServer();
} catch (IOException e) {
e.printStackTrace();
}
}
}
package ftp;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* 上傳進度
*
*/
public class ProgressListener {
private String fileName;
private volatile long bytesRead;
private volatile long contentLength;
public void update(long aBytesRead, long aContentLength) {
bytesRead = aBytesRead / 1024L;
contentLength = aContentLength / 1024L;
// long megaBytes = aBytesRead / 1048576L;
System.out.println("上傳或者下載檔案:" + fileName + ",檔案的大小:" + aBytesRead + "/" + aContentLength);
}
/**
*
* @param pIn
* @param pOut
* @return
* @throws IOException
*/
public long copy(InputStream in, OutputStream out, long size) {
byte[] buffer = new byte[8192];
long total = 0L;
int res;
try {
while (true) {
res = in.read(buffer);
if (res == -1) {
break;
}
if (res > 0) {
total += res;
if (out != null) {
out.write(buffer, 0, res);
System.out.println("檔案的大小" + size + "讀取的大小" + total);
update(total, size);
}
}
}
return total;
}catch (IOException e) {
return 0L;
} finally {
try {
in.close();
out.close();
} catch (IOException e) {
}
}
}
public long getBytesRead() {
return this.bytesRead;
}
public long getContentLength() {
return this.contentLength;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
}
使用過程中遇到一個問題,就是不知道為什麼不能例項化 FtpClient。但是把 FtpClient 改名字就好了。 *"錯誤: 在類 sun.net.ftp.FtpClient 中找不到主方法, 請將主方法定義為:public static void main(String[] args)。
相關推薦
Java 輕量級呼叫 FTP 上傳(安卓可用)
Edit:6-19,獨立一個標準 Java 專案了,Edit:5-13 更新:為避免與原有 rt.jar 衝突,特意把 sun.* 包名修改,參見在這裡的原始碼。今時今日 HTTP 斷點上傳、WebSocket 斷點上傳興起,FTP 協議大有被取代之勢,不過 FTP 顧名思義
Java中向ftp上傳、下載文件
utf-8 local iso password NPU 用戶名 用戶 失敗 集合 最近的一個項目跟ftp打交道很多,經常需要向ftp上傳、下載文件,現在總結一下公共方法。 上傳 /** * 文件上傳 * * @param ip
Java-Spring框架實現簡單的檔案上傳(圖片為例)
一、開發環境搭建 下載相應的jar包: 1.commons-fileupload 2.commons-io web.xml 檔案配置: <servlet> &
java接收圖片並上傳(接收)
enctype屬性 我們平常在使用form表單時會有一個enctype屬性,其預設是application/x-www-form-urlencoded w3c對這個編碼的定義是空格轉換為 "+" 加號,特殊符號轉換為 ASCII HEX 值,http伺服器是使用ASCII
java檔案上傳(解析request流)
無聊看nio的socket操作,看到了socket檔案傳輸想到之前做檔案上傳一直是用apache fileupload的元件,也沒有考慮過為什麼直接從request裡取不出檔案,現在想來原來是隻有從request中得到io流才能進行解析,現在自己寫了一個解析檔案上傳的過程,
ASP.NET Core 簡單實現七牛圖片上傳(FormData 和 Base64)
private stream public 圖片 ASP.NET Core 簡單實現七牛圖片上傳(FormData 和 Base64)七牛圖片上傳 SDK(.NET 版本):https://developer.qiniu.com/kodo/sdk/1237/csharpUpoladServic
node.js實現圖片上傳(包含縮略圖)
http close path return new tde log img thumb 圖片上傳 使用multiparty插件實現上傳 安裝multiparty npm i --save multiparty 代碼實現 const multiparty = requi
SpringMVC之檔案上傳(進度條顯示)
親測可用 1、mvc-config.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"
Django專案部分筆記上傳(未修改完)
pip install virtualenv 安裝虛擬環境 pip install virtualenv pip install virtualenvwrapper-win 安裝virtualenv的擴充套件管理包,用於更方便的管理虛擬環境 mkvirtualenv 虛擬環境名稱 建
curl的post請求檔案上傳(帶請求頭)
php中curl中檔案上傳 廢話不多說,看程式碼備註(記得區分是面向物件程式設計還是過程化程式設計哦) <?php // 返回資料的格式 header('content-type:application/json;charset=utf-8;'); $ch =
SpringBoot檔案上傳下載和多檔案上傳(圖文詳解)
最近在學習SpringBoot,以下是最近學習整理的實現檔案上傳下載的java程式碼: 1、開發環境: IDEA15+ Maven+JDK1.8 2、新建一個maven工程: 3、工程框架 4、pom.xml檔案依賴項 <proje
使用Jquery開源外掛實現檔案上傳(帶進度條)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <
H5 頭像上傳(支援裁切)
<!doctype html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial
Vue Quill Editor自定義圖片/視訊上傳(Element UI + OSS)、字型、字型大小、段落等
近期專案中需要使用富文字編輯器,開始想到的富文字編輯器是百度的UEditor,UEditor功能齊全、外掛多,但是圖片只能上傳到本地伺服器,如果需要上傳到其他伺服器需要改動原始碼,而且是PHP、JSP、ASP、.Net版本,同時UEditor體積過大壓縮包有
H5學習之路-圖片上傳(cropper、webuploader)
好久沒有寫部落格了,感覺都不習慣了。一方面是因為工作佔用的時間過多,另一方面是自己有點懶,沒有堅持。好了,少扯這些沒用的東西,直入主題唄。 筆者目前在公司會接觸到H5的開發,也就是手機端app的開發,但是用的H5,而非原生的方式,主要是節省開發時間,不必針對a
jQuery上傳外掛Uploadify使用Demo、本地上傳(ssm框架下)
maven/Java/web/bootstrapQQ群:566862629。希望更多人一起幫助我學習。 效果: 1. jar包匯入: <!-- 檔案上傳元件 --> &l
帶有進度條檔案上傳(UploadFile+AJAX+監聽器)
上傳頁面的jsp部分程式碼 <form action="/text2/UploadSoftware" id="testform" method="post" enctype="multipart/form-data" onsubmit="return show
django 實現頭像上傳(可以瀏覽圖片)
ext vat itl ada ipa before 選擇圖片 cti view center.html ------------------------------------- <div class="informations">
上傳(jquery.uploadify.js)
注:這是學習筆記!!! 首先引用js外掛jquery.uploadify.js 以下是js處理範例,詳細見官網 //上傳圖片附件 var folder = "/Upload/"; $(".
Android實現檔案上傳(支援多檔案)
大家在做android專案的時候,肯定會遇到檔案上傳(比如圖片,音樂等),今天我把我剛做的一個圖片上傳功能分享一下, 基本的流程就是:定義一個HttpClient→定義post請求(HttpPost)→post請求中新增引數(包括普通引數,檔案)→使用client傳送pos