FTP傳輸

      在〈FTP傳輸〉中尚無留言

FTP通訊協定驅動

在Android中, 若要使用 ftp 通訊協定下載及上傳檔案, 需安裝  Apache Commons Net 3.6 , 下載 commons-net-3.6-bin.zip 後解開檔案將commons-net-3.6.jar copy到 lib之下

權限

使用FTP, 需打開Internet權限, 且要將資料寫入SDCARD, 所以也需SDCARD權限. 注意, SDCARD屬危險權限, 需額外請求.

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

MahalFtp SDK

以下代碼, 可直接放入SDK中

package com.asuscomm.ftptest;

import android.util.Log;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.SocketException;

/** 本類別簡化FTP上傳下載功能
 * 開發日期 : 2017/10/01
 * @author Thomas (mahaljsp@gmail.com)
 */

final public class MahalFtp {
    private FTPClient ftpClient = null;
    //private static MahalFtp ftpUtilsInstance = null;
    private String ftpUrl;
    private int ftpPort;
    private String userName;
    private String userPassword;
    public MahalFtp(String ftpUrl, int ftpPort, String userName, String userPassword){
        this.ftpUrl = ftpUrl;
        this.ftpPort = ftpPort;
        this.userName = userName;
        this.userPassword = userPassword;
        ftpClient = new FTPClient();
        ftpClient.setConnectTimeout(5000);//設定timeout, 預設為0, 沒有timeout, 會一直等待連線
        ftpClient.setControlEncoding("UTF-8"); //一定要放在connect之前, 不然第一次一定是亂碼
    }
    public List<File>listFiles(String path){
        if (!ftpClient.isConnected()){
            if (!initFtp())return null;
        }
        try {
            ftpClient.setBufferSize(1024);
            ftpClient.enterLocalPassiveMode();
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            List<File>listFile=new ArrayList<>();
            for(FTPFile ftpFile: ftpClient.listFiles(path)){
                File file=new File(path,ftpFile.getName());
                listFile.add(file);
            }
            if(listFile.size()>0){
                return listFile;
            }
        }
        catch(IOException e){
            Log.d("Thomas", "listFile error : "+e.getMessage());
        }
        return null;
    }
    public long uploadFile(File remoteFile, File localFile){
        long size=0;
        if (!initFtp()){
            return 0;
        }
        try {
            ftpClient.setBufferSize(1024);
            ftpClient.enterLocalPassiveMode();
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            String[]paths=remoteFile.getParent().split("/");
            for (String s :paths) {
                ftpClient.makeDirectory(s);
                ftpClient.changeWorkingDirectory(s);
            }
            BufferedInputStream bis=new BufferedInputStream(new FileInputStream(localFile));

            //檢查遠端伺服器是否有相同的文件, 有的話表示上次沒傳成功, 需先砍掉
            FTPFile[] files=ftpClient.listFiles(remoteFile.getPath());
            if(files.length==1)ftpClient.deleteFile(remoteFile.getPath());

            ftpClient.storeFile(remoteFile.getPath(), bis);
            bis.close();
            size=ftpClient.listFiles(remoteFile.getPath())[0].getSize();
            ftpClient.logout();
            ftpClient.disconnect();

        }
        catch (IOException e) {Log.d("Thomas", "upLoadFile error : "+e.getMessage());}
        return size;
    }
    public boolean downLoadFile(File remoteFile, File localFile){
        if (!ftpClient.isConnected()){
            if (!initFtp()){
                return false;
            }
        }
        try {
            OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(localFile));
            ftpClient.retrieveFile(remoteFile.getPath(), outputStream);
            outputStream.close();
            ftpClient.logout();
            ftpClient.disconnect();
        }
        catch (IOException e) {Log.d("Thomas", "downloadFile error : "+e.getMessage());}
        return true;
    }
}

中文亂碼

如果是使用Filezilla Server架設伺服器的話, 請使用 0.9.60 版本. Filezilla 也只能用 UTF-8編碼. 網路上一大堆解決中文亂碼的方式, 都是沒啥用的.

想解決亂碼, 唯一的方法, 就是在Android 原始碼中, 在 connect 之前設定ftpClient.setControlEncoding(“UTF-8”);

如上面程式碼所示

主程式使用

請注意, 在操作ftp時, 如list file, download, upload, 都不可以在UI主執行緖中執行,  一定要開啟新的執行緒操作, 否則會發生不可預期的錯誤. 請參照如下代碼藍色部份

package com.asuscomm.ftptest;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import org.apache.commons.net.ftp.FTPFile;
import java.io.IOException;

public class MainActivity extends AppCompatActivity {
    MahalFtp ftp;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ftp = new MahalFtp("IP", 21, "帳號", "密碼");
        new Thread(()->{
            for (File file:ftp.listFiles("/disk_d")){
                Log.d("Thomas", file.getPath());
            }
            File remoteFile, localFile;
            //Download File
            remoteFile=new File("/disk_d", "wsshd1.jpg");
            localFile=new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),"wsshd1.jpg");
            ftp.downLoadFile(remoteFile, localFile);
            Log.d("Thomas", "download ok");
            //upload file
            remoteFile=new File("/disk_d/test1/test2", "song.mp3");
            localFile=new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC),"許茹芸.如果雲知道.mp3");
            ftp.uploadFile(remoteFile, localFile);
            Log.d("Thomas", "upload ok");
        }).start();
    } 
}

 完整代碼下載

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *