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