1. 程式人生 > >Android中FTP上傳、下載(含進度)

Android中FTP上傳、下載(含進度)

package com.ftp;

import java.io.File;
import java.io.IOException;
import java.util.LinkedList;

import com.ftp.FTP.DeleteFileProgressListener;
import com.ftp.FTP.DownLoadProgressListener;
import com.ftp.FTP.UploadProgressListener;

import android.app.Activity;
import android.os.Bundle;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity {

	private static final String TAG = "MainActivity";
	
	public static final String FTP_CONNECT_SUCCESSS = "ftp連線成功";
	public static final String FTP_CONNECT_FAIL = "ftp連線失敗";
	public static final String FTP_DISCONNECT_SUCCESS = "ftp斷開連線";
	public static final String FTP_FILE_NOTEXISTS = "ftp上檔案不存在";
	
	public static final String FTP_UPLOAD_SUCCESS = "ftp檔案上傳成功";
	public static final String FTP_UPLOAD_FAIL = "ftp檔案上傳失敗";
	public static final String FTP_UPLOAD_LOADING = "ftp檔案正在上傳";

	public static final String FTP_DOWN_LOADING = "ftp檔案正在下載";
	public static final String FTP_DOWN_SUCCESS = "ftp檔案下載成功";
	public static final String FTP_DOWN_FAIL = "ftp檔案下載失敗";
	
	public static final String FTP_DELETEFILE_SUCCESS = "ftp檔案刪除成功";
	public static final String FTP_DELETEFILE_FAIL = "ftp檔案刪除失敗";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        initView();
    }

    private void initView() {
    	
    	//上傳功能
    	//new FTP().uploadMultiFile為多檔案上傳
    	//new FTP().uploadSingleFile為單檔案上傳
		Button buttonUpload = (Button) findViewById(R.id.button_upload);        
    	buttonUpload.setOnClickListener(new OnClickListener() {            
            @Override
            public void onClick(View v) {

					new Thread(new Runnable() {			
						@Override
						public void run() {
							
		                    // 上傳
		                	File file = new File("/mnt/sdcard/ftpTest.docx");
		                    try {
		                    	
		                    	//單檔案上傳
								new FTP().uploadSingleFile(file, "/fff",new UploadProgressListener(){

									@Override
									public void onUploadProgress(String currentStep,long uploadSize,File file) {
										// TODO Auto-generated method stub
										Log.d(TAG, currentStep);										
										if(currentStep.equals(MainActivity.FTP_UPLOAD_SUCCESS)){
											Log.d(TAG, "-----shanchuan--successful");
										} else if(currentStep.equals(MainActivity.FTP_UPLOAD_LOADING)){
											long fize = file.length();
											float num = (float)uploadSize / (float)fize;
											int result = (int)(num * 100);
											Log.d(TAG, "-----shangchuan---"+result + "%");
										}
									}							
								});
							} catch (IOException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
							
						}
					}).start();
                     
            }
        });
    
    	//下載功能
    	Button buttonDown = (Button)findViewById(R.id.button_down);
    	buttonDown.setOnClickListener(new View.OnClickListener() {			
			@Override
			public void onClick(View v) {
				
				new Thread(new Runnable() {			
					@Override
					public void run() {
						
	                    // 下載
	                    try {
	                    	
	                    	//單檔案下載
	                    	new FTP().downloadSingleFile("/fff/ftpTest.docx","/mnt/sdcard/download/","ftpTest.docx",new DownLoadProgressListener(){

								@Override
								public void onDownLoadProgress(String currentStep, long downProcess, File file) {
									Log.d(TAG, currentStep);										
									if(currentStep.equals(MainActivity.FTP_DOWN_SUCCESS)){
										Log.d(TAG, "-----xiazai--successful");
									} else if(currentStep.equals(MainActivity.FTP_DOWN_LOADING)){
										Log.d(TAG, "-----xiazai---"+downProcess + "%");
									}
								}
	                    		
	                    	});	                    	
                    	
						} catch (Exception e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						
					}
				}).start();
				
			}
		});
    
    	//刪除功能
    	Button buttonDelete = (Button)findViewById(R.id.button_delete);
    	buttonDelete.setOnClickListener(new View.OnClickListener() {			
			@Override
			public void onClick(View v) {
				
				new Thread(new Runnable() {			
					@Override
					public void run() {
						
	                    // 刪除
	                    try {

	                    	new FTP().deleteSingleFile("/fff/ftpTest.docx",new DeleteFileProgressListener(){

								@Override
								public void onDeleteProgress(String currentStep) {
									Log.d(TAG, currentStep);										
									if(currentStep.equals(MainActivity.FTP_DELETEFILE_SUCCESS)){
										Log.d(TAG, "-----shanchu--success");
									} else if(currentStep.equals(MainActivity.FTP_DELETEFILE_FAIL)){
										Log.d(TAG, "-----shanchu--fail");
									}
								}
	                    		
	                    	});	                    	
                    	
						} catch (Exception e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						
					}
				}).start();
				
			}
		});
    
    }
}

2. FTP

package com.ftp;

import java.io.BufferedInputStream;
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 java.util.Date;
import java.util.LinkedList;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

public class FTP {
	/**
	 * 伺服器名.
	 */
	private String hostName;

	/**
	 * 埠號
	 */
	private int serverPort;

	/**
	 * 使用者名稱.
	 */
	private String userName;

	/**
	 * 密碼.
	 */
	private String password;

	/**
	 * FTP連線.
	 */
	private FTPClient ftpClient;

	public FTP() {
		this.hostName = "192.168.1.101";
		this.serverPort = 21;
		this.userName = "admin";
		this.password = "1234";
		this.ftpClient = new FTPClient();
	}

	// -------------------------------------------------------檔案上傳方法------------------------------------------------

	/**
	 * 上傳單個檔案.
	 * 
	 * @param localFile
	 *            本地檔案
	 * @param remotePath
	 *            FTP目錄
	 * @param listener
	 *            監聽器
	 * @throws IOException
	 */
	public void uploadSingleFile(File singleFile, String remotePath,
			UploadProgressListener listener) throws IOException {

		// 上傳之前初始化
		this.uploadBeforeOperate(remotePath, listener);

		boolean flag;
		flag = uploadingSingle(singleFile, listener);
		if (flag) {
			listener.onUploadProgress(MainActivity.FTP_UPLOAD_SUCCESS, 0,
					singleFile);
		} else {
			listener.onUploadProgress(MainActivity.FTP_UPLOAD_FAIL, 0,
					singleFile);
		}

		// 上傳完成之後關閉連線
		this.uploadAfterOperate(listener);
	}

	/**
	 * 上傳多個檔案.
	 * 
	 * @param localFile
	 *            本地檔案
	 * @param remotePath
	 *            FTP目錄
	 * @param listener
	 *            監聽器
	 * @throws IOException
	 */
	public void uploadMultiFile(LinkedList<File> fileList, String remotePath,
			UploadProgressListener listener) throws IOException {

		// 上傳之前初始化
		this.uploadBeforeOperate(remotePath, listener);

		boolean flag;

		for (File singleFile : fileList) {
			flag = uploadingSingle(singleFile, listener);
			if (flag) {
				listener.onUploadProgress(MainActivity.FTP_UPLOAD_SUCCESS, 0,
						singleFile);
			} else {
				listener.onUploadProgress(MainActivity.FTP_UPLOAD_FAIL, 0,
						singleFile);
			}
		}

		// 上傳完成之後關閉連線
		this.uploadAfterOperate(listener);
	}

	/**
	 * 上傳單個檔案.
	 * 
	 * @param localFile
	 *            本地檔案
	 * @return true上傳成功, false上傳失敗
	 * @throws IOException
	 */
	private boolean uploadingSingle(File localFile,
			UploadProgressListener listener) throws IOException {
		boolean flag = true;
		// 不帶進度的方式
		// // 建立輸入流
		// InputStream inputStream = new FileInputStream(localFile);
		// // 上傳單個檔案
		// flag = ftpClient.storeFile(localFile.getName(), inputStream);
		// // 關閉檔案流
		// inputStream.close();

		// 帶有進度的方式
		BufferedInputStream buffIn = new BufferedInputStream(
				new FileInputStream(localFile));
		ProgressInputStream progressInput = new ProgressInputStream(buffIn,
				listener, localFile);
		flag = ftpClient.storeFile(localFile.getName(), progressInput);
		buffIn.close();

		return flag;
	}
	
	/**
	 * 上傳檔案之前初始化相關引數
	 * 
	 * @param remotePath
	 *            FTP目錄
	 * @param listener
	 *            監聽器
	 * @throws IOException
	 */
	private void uploadBeforeOperate(String remotePath,
			UploadProgressListener listener) throws IOException {

		// 開啟FTP服務
		try {
			this.openConnect();
			listener.onUploadProgress(MainActivity.FTP_CONNECT_SUCCESSS, 0,
					null);
		} catch (IOException e1) {
			e1.printStackTrace();
			listener.onUploadProgress(MainActivity.FTP_CONNECT_FAIL, 0, null);
			return;
		}

		// 設定模式
		ftpClient.setFileTransferMode(org.apache.commons.net.ftp.FTP.STREAM_TRANSFER_MODE);
		// FTP下建立資料夾
		ftpClient.makeDirectory(remotePath);
		// 改變FTP目錄
		ftpClient.changeWorkingDirectory(remotePath);
		// 上傳單個檔案

	}

	/**
	 * 上傳完成之後關閉連線
	 * 
	 * @param listener
	 * @throws IOException
	 */
	private void uploadAfterOperate(UploadProgressListener listener)
			throws IOException {
		this.closeConnect();
		listener.onUploadProgress(MainActivity.FTP_DISCONNECT_SUCCESS, 0, null);
	}

	// -------------------------------------------------------檔案下載方法------------------------------------------------

	/**
	 * 下載單個檔案,可實現斷點下載.
	 * 
	 * @param serverPath
	 *            Ftp目錄及檔案路徑
	 * @param localPath
	 *            本地目錄
	 * @param fileName       
	 *            下載之後的檔名稱
	 * @param listener
	 *            監聽器
	 * @throws IOException
	 */
	public void downloadSingleFile(String serverPath, String localPath, String fileName, DownLoadProgressListener listener)
			throws Exception {

		// 開啟FTP服務
		try {
			this.openConnect();
			listener.onDownLoadProgress(MainActivity.FTP_CONNECT_SUCCESSS, 0, null);
		} catch (IOException e1) {
			e1.printStackTrace();
			listener.onDownLoadProgress(MainActivity.FTP_CONNECT_FAIL, 0, null);
			return;
		}

		// 先判斷伺服器檔案是否存在
		FTPFile[] files = ftpClient.listFiles(serverPath);
		if (files.length == 0) {
			listener.onDownLoadProgress(MainActivity.FTP_FILE_NOTEXISTS, 0, null);
			return;
		}

		//建立本地資料夾
		File mkFile = new File(localPath);
		if (!mkFile.exists()) {
			mkFile.mkdirs();
		}

		localPath = localPath + fileName;
		// 接著判斷下載的檔案是否能斷點下載
		long serverSize = files[0].getSize(); // 獲取遠端檔案的長度
		File localFile = new File(localPath);
		long localSize = 0;
		if (localFile.exists()) {
			localSize = localFile.length(); // 如果本地檔案存在,獲取本地檔案的長度
			if (localSize >= serverSize) {
				File file = new File(localPath);
				file.delete();
			}
		}
		
		// 進度
		long step = serverSize / 100;
		long process = 0;
		long currentSize = 0;
		// 開始準備下載檔案
		OutputStream out = new FileOutputStream(localFile, true);
		ftpClient.setRestartOffset(localSize);
		InputStream input = ftpClient.retrieveFileStream(serverPath);
		byte[] b = new byte[1024];
		int length = 0;
		while ((length = input.read(b)) != -1) {
			out.write(b, 0, length);
			currentSize = currentSize + length;
			if (currentSize / step != process) {
				process = currentSize / step;
				if (process % 5 == 0) {  //每隔%5的進度返回一次
					listener.onDownLoadProgress(MainActivity.FTP_DOWN_LOADING, process, null);
				}
			}
		}
		out.flush();
		out.close();
		input.close();
		
		// 此方法是來確保流處理完畢,如果沒有此方法,可能會造成現程式死掉
		if (ftpClient.completePendingCommand()) {
			listener.onDownLoadProgress(MainActivity.FTP_DOWN_SUCCESS, 0, new File(localPath));
		} else {
			listener.onDownLoadProgress(MainActivity.FTP_DOWN_FAIL, 0, null);
		}

		// 下載完成之後關閉連線
		this.closeConnect();
		listener.onDownLoadProgress(MainActivity.FTP_DISCONNECT_SUCCESS, 0, null);

		return;
	}

	// -------------------------------------------------------檔案刪除方法------------------------------------------------

	/**
	 * 刪除Ftp下的檔案.
	 * 
	 * @param serverPath
	 *            Ftp目錄及檔案路徑
	 * @param listener
	 *            監聽器
	 * @throws IOException
	 */
	public void deleteSingleFile(String serverPath, DeleteFileProgressListener listener)
			throws Exception {

		// 開啟FTP服務
		try {
			this.openConnect();
			listener.onDeleteProgress(MainActivity.FTP_CONNECT_SUCCESSS);
		} catch (IOException e1) {
			e1.printStackTrace();
			listener.onDeleteProgress(MainActivity.FTP_CONNECT_FAIL);
			return;
		}

		// 先判斷伺服器檔案是否存在
		FTPFile[] files = ftpClient.listFiles(serverPath);
		if (files.length == 0) {
			listener.onDeleteProgress(MainActivity.FTP_FILE_NOTEXISTS);
			return;
		}
		
		//進行刪除操作
		boolean flag = true;
		flag = ftpClient.deleteFile(serverPath);
		if (flag) {
			listener.onDeleteProgress(MainActivity.FTP_DELETEFILE_SUCCESS);
		} else {
			listener.onDeleteProgress(MainActivity.FTP_DELETEFILE_FAIL);
		}
		
		// 刪除完成之後關閉連線
		this.closeConnect();
		listener.onDeleteProgress(MainActivity.FTP_DISCONNECT_SUCCESS);
		
		return;
	}

	// -------------------------------------------------------開啟關閉連線------------------------------------------------

	/**
	 * 開啟FTP服務.
	 * 
	 * @throws IOException
	 */
	public void openConnect() throws IOException {
		// 中文轉碼
		ftpClient.setControlEncoding("UTF-8");
		int reply; // 伺服器響應值
		// 連線至伺服器
		ftpClient.connect(hostName, serverPort);
		// 獲取響應值
		reply = ftpClient.getReplyCode();
		if (!FTPReply.isPositiveCompletion(reply)) {
			// 斷開連線
			ftpClient.disconnect();
			throw new IOException("connect fail: " + reply);
		}
		// 登入到伺服器
		ftpClient.login(userName, password);
		// 獲取響應值
		reply = ftpClient.getReplyCode();
		if (!FTPReply.isPositiveCompletion(reply)) {
			// 斷開連線
			ftpClient.disconnect();
			throw new IOException("connect fail: " + reply);
		} else {
			// 獲取登入資訊
			FTPClientConfig config = new FTPClientConfig(ftpClient
					.getSystemType().split(" ")[0]);
			config.setServerLanguageCode("zh");
			ftpClient.configure(config);
			// 使用被動模式設為預設
			ftpClient.enterLocalPassiveMode();
			// 二進位制檔案支援
			ftpClient
					.setFileType(org.apache.commons.net.ftp.FTP.BINARY_FILE_TYPE);
		}
	}

	/**
	 * 關閉FTP服務.
	 * 
	 * @throws IOException
	 */
	public void closeConnect() throws IOException {
		if (ftpClient != null) {
			// 退出FTP
			ftpClient.logout();
			// 斷開連線
			ftpClient.disconnect();
		}
	}

	// ---------------------------------------------------上傳、下載、刪除監聽---------------------------------------------
	
	/*
	 * 上傳進度監聽
	 */
	public interface UploadProgressListener {
		public void onUploadProgress(String currentStep, long uploadSize, File file);
	}

	/*
	 * 下載進度監聽
	 */
	public interface DownLoadProgressListener {
		public void onDownLoadProgress(String currentStep, long downProcess, File file);
	}

	/*
	 * 檔案刪除監聽
	 */
	public interface DeleteFileProgressListener {
		public void onDeleteProgress(String currentStep);
	}

}

3. ProgressInputStream

package com.ftp;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import com.ftp.FTP.UploadProgressListener;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

public class ProgressInputStream extends InputStream {

    private static final int TEN_KILOBYTES = 1024 * 10;  //每上傳10K返回一次

    private InputStream inputStream;

    private long progress;
    private long lastUpdate;

    private boolean closed;
    
    private UploadProgressListener listener;
    private File localFile;

    public ProgressInputStream(InputStream inputStream,UploadProgressListener listener,File localFile) {
        this.inputStream = inputStream;
        this.progress = 0;
        this.lastUpdate = 0;
        this.listener = listener;
        this.localFile = localFile;
        
        this.closed = false;
    }

    @Override
    public int read() throws IOException {
        int count = inputStream.read();
        return incrementCounterAndUpdateDisplay(count);
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        int count = inputStream.read(b, off, len);
        return incrementCounterAndUpdateDisplay(count);
    }

    @Override
    public void close() throws IOException {
        super.close();
        if (closed)
            throw new IOException("already closed");
        closed = true;
    }

    private int incrementCounterAndUpdateDisplay(int count) {
        if (count > 0)
            progress += count;
        lastUpdate = maybeUpdateDisplay(progress, lastUpdate);
        return count;
    }

    private long maybeUpdateDisplay(long progress, long lastUpdate) {
        if (progress - lastUpdate > TEN_KILOBYTES) {
            lastUpdate = progress;
            this.listener.onUploadProgress(MainActivity.FTP_UPLOAD_LOADING, progress, this.localFile);
        }
        return lastUpdate;
    }
    
  
    
}