1. 程式人生 > >Java 輕量級呼叫 FTP 上傳(安卓可用)

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