1、前期准备
2、登录
3、上传
4、下载
5、删除
6、常用的一些方法
1、前期准备
一般自己搭建FTP服务器采用第三方的软件:Serv-U 或Xlight FTP Server,也可以自己在电脑上搭建。
在实际使用时需要先下载commons-net-3.3.jar包,本文中的事例代码已封装成FTPutils类,读者实际使用,可直接下载。
①:下载jar包:commons-net-3.3.jar
②:在AM中添加权限(如果是6.0及以上需要动态申请):
<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permissionandroid:name="android.permission.INTERNET"/>
<uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE"/>
2、登录
一般针对FTP都是抽取为一个工具类使用,对于一些参数的初始化设置,都是在其构造方法中完成,主要包括以下操作:
① 参数初始化
public void useCompressedTransfer() {
try {
mFtpClient.setFileTransferMode(org.apache.commons.net.ftp.FTP.COMPRESSED_TRANSFER_MODE);
// 使用被动模式设为默认
mFtpClient.enterLocalPassiveMode();
// 二进制文件支持
mFtpClient.setFileType(FTP.BINARY_FILE_TYPE);
//设置缓存
mFtpClient.setBufferSize(1024);
//设置编码格式,防止中文乱码
mFtpClient.setControlEncoding("UTF-8");
//设置连接超时时间
this.mFtpClient.setConnectTimeout(10 * 1000);
//设置数据传输超时时间
// mFtpClient.setDataTimeout(10*1000);
} catch (Exception e) {
e.printStackTrace();
}
}
②登录
public boolean connect(String ip, int port,String userName, String pass) {
boolean status = false;
try {
if(!mFtpClient.isConnected()){
mFtpClient.connect(ip,port);
status = mFtpClient.login(userName, pass);
Constant.ftpLoginResult = status;
}
Log.i(TAG, "connect: " + status);
} catch (IOException e) {
e.printStackTrace();
}
return status;
}
3、上传
①:通过流上传文件
public void uploadFile(final InputStream srcFileStream, final String name) {
new Thread(new Runnable() {
@Override
public void run() {
try {
File file = new File( name );
mFtpClient.setFileType(FTP.BINARY_FILE_TYPE); //图片支持二进制上传 如果采用ASCII_FILE_TYPE(默认),虽然上传后有数据,但图片无法打开
boolean status = mFtpClient.storeFile(name, srcFileStream);
srcFileStream.close();
} catch (Exception e) {
Log.i(TAG, "run: "+e.toString());
}
}
}).start();
}
注意: 图片支持二进制上传在setFileType时如果采用ASCII_FILE_TYPE(默认),虽然上传后有数据,但图片无法打开。
②:通过URI方式
public void uploadFile(String uri, String name) throws Exception {
try {
File file = new File(uri);
mFtpClient.setFileType(org.apache.commons.net.ftp.FTP.BINARY_FILE_TYPE);
FileInputStream srcFileStream = new FileInputStream(file);
boolean status = mFtpClient.storeFile(name, srcFileStream);
srcFileStream.close();
} catch (Exception e) {
throw e;
}
}
③:上传至FTP指定文件夹中
/**
* FTP上传文件
* filePathName 文件路径方式
* @param filePathName
* @return
*/
public boolean ftpUploadFile(String filePathName){
boolean result = false;
try {
File file = new File( filePathName );
String dataDirectory = file.getName().substring(0,8);
if (file.exists()) {
FileInputStream fileInputStream = new FileInputStream(file);
uploadDirectoryFile(fileInputStream, dataDirectory, file.getName());
result = true; //上传成功
} else {
Log.i(TAG, "ftpUploadFile: 文件路径不存在");
}
} catch (Exception e) {
Log.i(TAG, "ftpUploadFile: "+"Failure : " + e.getLocalizedMessage());
}
return result ;
}
/**
* 上传文件夹
*文件流 上传后指定根目录 文件名称
* @param srcFileStream 文件流
* @param directoryName ftp存储的文件夹名称
* @param name ftp存储的文件名称
* @throws Exception
*/
public void uploadDirectoryFile(InputStream srcFileStream, String directoryName, String name) throws Exception {
try {
mFtpClient.setFileType(org.apache.commons.net.ftp.FTP.BINARY_FILE_TYPE);
//判断当前FTP工作目录
String pwd = mFtpClient.printWorkingDirectory();
if(pwd!=null){
if(!("/"+Constant.ftpDirectoryFile).equals(pwd)){
getDirectoryExist(Constant.ftpDirectoryFile);
}
}
getDirectoryExist(directoryName);
mFtpClient.storeFile(name, srcFileStream)
changeToParentDirectory();
srcFileStream.close();
} catch (Exception e) {
throw e;
}
}
注意:在文件上传中需要注意,在FTP默认上传的根目录是服务器的根目录文件夹下,如果我们需要根据业务需要重置文件夹路径,就需要以下几步:
第一:查看根目录指定文件夹是否存在
mFtpClient.makeDirectory(dir)
第二:如果存在就将当期的上传目录。切换至需要保存的文件夹目录中
mFtpClient.changeWorkingDirectory(DirectoryName)
以上两步也是getDirectoryExist(directoryName)方法完成的事情,确定好当前的上传目录是我们需要保存的目录后,就可以执行mFtpClient.storeFile(name, srcFileStream)操作。
重点强调一下,在实际使用中,比如我们需要按照日期来上传文件,此时需要按照日期来创建文件夹并将相应的内容存储在该文件夹下,这里需要特别注意WorkingDirectory的概念,最好实际打印出该文件夹名称,否则容易导致上传的内容和创建的文件夹混乱情况。
4、下载
/**
* 下载单个文件,可实现断点下载.
*
* @param serverPath Ftp目录及文件路径(文件夹+文件名)
*
* @param localPath 本地目录文件夹目录(文件夹)
*
* @param fileName 下载之后的文件名称(文件名)
*
* @param listener 监听器
*
* @throws IOException
*/
public void downloadSingleFile(String serverPath, String localPath, String fileName, FtpProgressListener listener) throws Exception {
listener.onFtpProgress(Constant.FTP_CONNECT_SUCCESS, 0, null);
// 先判断服务器文件是否存在
FTPFile[] files = mFtpClient.listFiles(serverPath);
if (files!=null &&files.length == 0) {
listener.onFtpProgress(Constant.FTP_FILE_NOTEXISTS, 0, null);
return;
}
// 创建本地文件夹
File mkFile = new File(localPath);
if (!mkFile.exists()) {
boolean ismake=mkFile.mkdirs();
Log.i(TAG,"是否存在"+ismake);
}
localPath = localPath + File.separator+fileName;
// 接着判断下载的文件是否能断点下载
long serverSize = files[0].getSize(); // 获取远程文件的长度
File localFile = new File(localPath);
long localSize = 0;
if (localFile.exists()) {
localSize = localFile.length(); // 如果本地文件存在,获取本地文件的长度
if (localSize >= serverSize) {
listener.onFtpProgress(Constant.LOCAL_FILE_AIREADY_COMPLETE, 0, localFile);
localFile.delete();
localFile.createNewFile();
localSize=0;
}else {
listener.onFtpProgress(Constant.FTP_DOWN_CONTINUE, 0, null);
}
}else {
localFile.createNewFile();
}
// 进度
long step = serverSize / 100;
long process = 0;
long currentSize = localSize;
// 开始准备下载文件
OutputStream out = new FileOutputStream(localFile, true);
mFtpClient.setRestartOffset(localSize);
InputStream input = mFtpClient.retrieveFileStream(serverPath);//在调用此方法后,一定要在流关闭后再调用completePendingCommand结束整个事务
byte[] b = new byte[1024];
int length = 0;
while ((length = input.read(b)) !=-1) {
Log.i(TAG, "downloadSingleFile:正在下载"+step);
out.write(b, 0, length);
currentSize = currentSize + length;
if (currentSize / step != process) {
process = currentSize / step;
if (process % 1 == 0) { // 每隔%1的进度返回一次
listener.onFtpProgress(Constant.FTP_DOWN_LOADING, process, null);
}
}
}
Log.i(TAG, "downloadSingleFile: 下载完毕");
out.flush();
out.close();
input.close();
// 此方法是来确保流处理完毕,如果没有此方法,可能会造成现程序死掉
if (mFtpClient.completePendingCommand()&&localFile.length()==serverSize) {
listener.onFtpProgress(Constant.FTP_DOWN_SUCCESS, process, localFile);
} else if(localFile.length()!=serverSize){
listener.onFtpProgress(Constant.FTP_DOWN_SIZEOUT,serverSize,localFile);
}
else {
listener.onFtpProgress(Constant.FTP_DOWN_FAIL, 0, null);
}
// 下载完成之后关闭连接
// this.disconnect();
listener.onFtpProgress(Constant.FTP_DISCONNECT_SUCCESS, 0, null);
return;
}
/**
* 删除Ftp下的文件.
*
* @param serverPath
* Ftp目录及文件路径
* @param listener
* 监听器
* @throws IOException
*/
public void deleteSingleFile(String serverPath, FtpDeleteFileListener listener) throws Exception {
listener.onFtpDelete(Constant.FTP_CONNECT_SUCCESS);
// 先判断服务器文件是否存在
FTPFile[] files = mFtpClient.listFiles(serverPath);
if (files.length == 0) {
listener.onFtpDelete(Constant.FTP_FILE_NOTEXISTS);
return;
}
// 进行删除操作
boolean flag = true;
flag = mFtpClient.deleteFile(serverPath);
if (flag) {
listener.onFtpDelete(Constant.FTP_DELETEFILE_SUCCESS);
} else {
listener.onFtpDelete(Constant.FTP_DELETEFILE_FAIL);
}
listener.onFtpDelete(Constant.FTP_DISCONNECT_SUCCESS);
return;
}
5、删除
/**
*删除Ftp下的文件.
*@paramserverPath
*Ftp目录及文件路径
*@paramlistener
*监听器
*@throwsIOException
*/
public void deleteSingleFile(String serverPath,FtpDeleteFileListenerlistener)throwsException{
//先判断服务器文件是否存在
FTPFile [] files=mFtpClient.listFiles(serverPath);
if(files.length==0){
listener.onFtpDelete(Constant.FTP_FILE_NOTEXISTS);
return;
}
//进行删除操作
boolean flag=true;
flag=mFtpClient.deleteFile(serverPath);
if(flag){
listener.onFtpDelete(Constant.FTP_DELETEFILE_SUCCESS);
}else{
listener.onFtpDelete(Constant.FTP_DELETEFILE_FAIL);
}
listener.onFtpDelete(Constant.FTP_DISCONNECT_SUCCESS);
return;
}
6、常用的一些方法
以下总结的9种小方法是在实际使用中经常用到的,将其提取便于调用。其中mFtpClient是指在建立好登录连接操作以后的FTPClient对象,实际使用时需要判断登录是否连接,对象是否为空等,当然也根据需要提取出FTPClient中的常用API抽取为实用的方法。
①获取根目录下所有文件的名称
public String[]listName()throwsException{
try{
return mFtpClient.listNames();
}catch(Exceptione){
throwe;
}}
② 获取根目录下所有文件的名称
public FTPFile[]listName(Stringfile)throws Exception{
try{
FTPFile[] ftpFiles = mFtpClient.listFiles(file);
return ftpFiles;
}catch(Exceptione){
throwe;}}
③ 断FTP中是否包含上传的文件夹
try{
booleanb=makeDir(DirectoryName);
mFtpClient.changeWorkingDirectory(DirectoryName);
}catch(Exceptione){
e.printStackTrace();
}
④ 获取FTP当前工作的根目录
public String getFTPfile(){
String FTPWorkingPath="";
try{
FTPWorkingPath=mFtpClient.printWorkingDirectory();
}catch(IOExceptione){
e.printStackTrace();
}
return FTPWorkingPath;
}
⑤ 更改文件的存储路径
public void ftputilsChangeWorkingDirectory(StringdirectoryName){
try{
mFtpClient.changeWorkingDirectory(directoryName);
}catch(IOExceptione){
e.printStackTrace();
}
}
⑥ 创建文件夹
public boolean makeDir(Stringdir)throwsException{
try{
Return mFtpClient.makeDirectory(dir);
}catch(Exceptione){
throwe;
}}
⑦ 更改至父目录下
public void changeToParentDirectory(){
try{
mFtpClient.changeToParentDirectory();
}catch(IOExceptione){
}}
⑧ 断开连接
public void disconnect(){
try{
if(mFtpClient!=null&&mFtpClient.isConnected()){
mFtpClient.logout();//退出
mFtpClient.disconnect();//断开
}}catch(Exceptione){
e.printStackTrace();
}}
⑨ 判断是否登录
public boolean isConnected(){
boolean connected=false;
if(mFtpClient!=null){
mFtpClient.isConnected();
}
return connected;
}