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(); } }