修复 ftp文件夹下载问题

pull/330/head
AriaLyy 7 years ago
parent 3fa49f11dd
commit 8fd64a9147
  1. 12
      Aria/src/main/java/com/arialyy/aria/core/FtpUrlEntity.java
  2. 2
      Aria/src/main/java/com/arialyy/aria/core/TaskManager.java
  3. 24
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFtpInfoThread.java
  4. 68
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFtpThreadTask.java
  5. 2
      Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java
  6. 1
      Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java
  7. 81
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsGroupUtil.java
  8. 8
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java
  9. 16
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java
  10. 4
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirInfoThread.java
  11. 17
      Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java
  12. 8
      app/src/main/java/com/arialyy/simple/download/FtpDownloadActivity.java
  13. 2
      app/src/main/java/com/arialyy/simple/download/group/FTPDirDownloadActivity.java

@ -23,7 +23,7 @@ import java.net.InetAddress;
* Created by Aria.Lao on 2017/10/24.
* ftp url 信息链接实体
*/
public class FtpUrlEntity {
public class FtpUrlEntity implements Cloneable {
public String remotePath;
@ -67,4 +67,14 @@ public class FtpUrlEntity {
* 有效的ip地址
*/
public InetAddress validAddr;
@Override public FtpUrlEntity clone() {
FtpUrlEntity entity = null;
try {
entity = (FtpUrlEntity) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return entity;
}
}

@ -51,7 +51,7 @@ public class TaskManager {
* @param task 任务
* @return {@code true}添加成功
*/
public boolean addTask(String key, AbsTask task) {
public <T extends AbsTask> boolean addTask(String key, Class<T> clazz, T task) {
String hash = CommonUtil.keyToHashKey(key);
if (map.keySet().contains(hash)) {
ALog.e(TAG, "任务【" + key + "】已存在");

@ -70,17 +70,30 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
FTPClient client = null;
try {
client = createFtpClient();
if (client == null) return;
if (client == null) {
failDownload("创建FTP客户端失败", true);
return;
}
String remotePath =
new String(setRemotePath().getBytes(charSet), AbsFtpThreadTask.SERVER_CHARSET);
FTPFile[] files = client.listFiles(remotePath);
boolean isExist = files.length != 0;
if (!isExist && !isUpload) {
client.disconnect();
failDownload("文件不存在,任务链接【" + mTaskEntity.urlEntity.url + "】", false);
FTPFile[] files1 = client.listFiles();
if (files1.length > 0) {
ALog.i(TAG, "路径【" + setRemotePath() + "】该下文件列表 ===================================");
for (FTPFile file : files1) {
ALog.d(TAG, file.toString());
}
ALog.i(TAG, "================================= --end-- ===================================");
}
client.disconnect();
return;
}
mSize = getFileSize(files, client, remotePath);
//为了防止编码错乱,需要使用原始字符串
mSize = getFileSize(files, client, setRemotePath());
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
if (isUpload) {
@ -159,11 +172,16 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
boolean loginSuccess = true;
if (urlEntity.needLogin) {
try {
if (TextUtils.isEmpty(urlEntity.account)) {
loginSuccess = client.login(urlEntity.user, urlEntity.password);
} else {
loginSuccess = client.login(urlEntity.user, urlEntity.password, urlEntity.account);
}
} catch (IOException e) {
ALog.e(TAG, client.getReplyString());
return null;
}
}
if (!loginSuccess) {

@ -20,8 +20,10 @@ import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IEventListener;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.ALog;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
@ -32,7 +34,8 @@ import org.apache.commons.net.ftp.FTPReply;
*/
public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
extends AbsThreadTask<ENTITY, TASK_ENTITY> {
protected String charSet, serverIp, port;
private final String TAG = "AbsFtpThreadTask";
protected String charSet, port;
/**
* FTP 服务器编码
*/
@ -46,11 +49,34 @@ public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTI
/**
* 构建FTP客户端
*/
protected FTPClient createClient() throws IOException {
FTPClient client = new FTPClient();
protected FTPClient createClient() {
FTPClient client = null;
final FtpUrlEntity urlEntity = mTaskEntity.urlEntity;
if (urlEntity.validAddr == null) {
try {
InetAddress[] ips = InetAddress.getAllByName(urlEntity.hostName);
client = connect(new FTPClient(), ips, 0, Integer.parseInt(urlEntity.port));
if (client == null) {
return null;
}
} catch (UnknownHostException e) {
e.printStackTrace();
}
} else {
client = new FTPClient();
try {
client.connect(urlEntity.validAddr, Integer.parseInt(urlEntity.port));
} catch (IOException e) {
ALog.e(TAG, ALog.getExceptionString(e));
return null;
}
}
if (client == null){
return null;
}
try {
if (urlEntity.needLogin) {
if (TextUtils.isEmpty(urlEntity.account)) {
client.login(urlEntity.user, urlEntity.password);
@ -58,7 +84,6 @@ public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTI
client.login(urlEntity.user, urlEntity.password, urlEntity.account);
}
}
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
@ -76,6 +101,39 @@ public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTI
client.enterLocalPassiveMode();
client.setFileType(FTP.BINARY_FILE_TYPE);
client.setControlKeepAliveTimeout(5);
} catch (IOException e) {
e.printStackTrace();
}
return client;
}
/**
* 连接到ftp服务器
*/
private FTPClient connect(FTPClient client, InetAddress[] ips, int index, int port) {
try {
client.connect(ips[index], port);
mTaskEntity.urlEntity.validAddr = ips[index];
return client;
} catch (IOException e) {
try {
if (client.isConnected()) {
client.disconnect();
}
} catch (IOException e1) {
e1.printStackTrace();
}
if (index + 1 >= ips.length) {
ALog.w(TAG, "遇到[ECONNREFUSED-连接被服务器拒绝]错误,已没有其他地址,链接失败");
return null;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
ALog.w(TAG, "遇到[ECONNREFUSED-连接被服务器拒绝]错误,正在尝试下一个地址");
return connect(new FTPClient(), ips, index + 1, port);
}
}
}

@ -16,7 +16,6 @@
package com.arialyy.aria.core.download;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog;
@ -35,7 +34,6 @@ public class FtpDirDownloadTarget
mTargetName = targetName;
mTaskEntity.urlEntity = CommonUtil.getFtpUrlInfo(url);
mTaskEntity.requestType = AbsTaskEntity.FTP_DIR;
Log.d(TAG, "FTP_TARGET_MD5:" + mTaskEntity.hashCode());
}
private void init(String key) {

@ -17,7 +17,6 @@ package com.arialyy.aria.core.download;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;

@ -43,6 +43,15 @@ import java.util.concurrent.Executors;
*/
public abstract class AbsGroupUtil implements IUtil {
private final String TAG = "AbsGroupUtil";
/**
* FTP文件夹
*/
protected int FTP_DIR = 0xa1;
/**
* HTTP 任务组
*/
protected int HTTP_GROUP = 0xa2;
/**
* 任务组所有任务总长度
*/
@ -50,7 +59,7 @@ public abstract class AbsGroupUtil implements IUtil {
long mCurrentLocation = 0;
private ExecutorService mExePool;
protected IDownloadGroupListener mListener;
protected DownloadGroupTaskEntity mTaskEntity;
protected DownloadGroupTaskEntity mGTEntity;
private boolean isRunning = false;
private Timer mTimer;
/**
@ -82,34 +91,32 @@ public abstract class AbsGroupUtil implements IUtil {
private int mFailNum = 0;
//停止的任务数
private int mStopNum = 0;
//实际的下载任务数
int mActualTaskNum = 0;
//初始化完成的任务数
int mInitNum = 0;
// 初始化失败的任务数
int mInitFailNum = 0;
//任务组大小
int mGroupSize = 0;
AbsGroupUtil(IDownloadGroupListener listener, DownloadGroupTaskEntity taskEntity) {
AbsGroupUtil(IDownloadGroupListener listener, DownloadGroupTaskEntity groupEntity) {
mListener = listener;
mTaskEntity = taskEntity;
mGTEntity = groupEntity;
mExePool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
List<DownloadTaskEntity> tasks =
DbEntity.findDatas(DownloadTaskEntity.class, "groupName=?", mTaskEntity.key);
DbEntity.findDatas(DownloadTaskEntity.class, "groupName=?", mGTEntity.key);
if (tasks != null && !tasks.isEmpty()) {
for (DownloadTaskEntity te : tasks) {
te.removeFile = mTaskEntity.removeFile;
te.removeFile = mGTEntity.removeFile;
if (te.getEntity() == null) continue;
mTasksMap.put(te.getEntity().getUrl(), te);
}
}
mGroupSize = mTaskEntity.entity.getSubTask().size();
mTotalLen = taskEntity.getEntity().getFileSize();
mGroupSize = mGTEntity.entity.getSubTask().size();
mTotalLen = groupEntity.getEntity().getFileSize();
isNeedLoadFileSize = mTotalLen <= 1;
for (DownloadEntity entity : mTaskEntity.entity.getSubTask()) {
for (DownloadEntity entity : mGTEntity.entity.getSubTask()) {
File file = new File(entity.getDownloadPath());
if (entity.getState() == IEntity.STATE_COMPLETE && file.exists()) {
mCompleteNum++;
@ -126,10 +133,20 @@ public abstract class AbsGroupUtil implements IUtil {
updateFileSize();
}
/**
* 获取任务类型
*
* @return {@link #FTP_DIR}{@link #HTTP_GROUP}
*/
abstract int getTaskType();
/**
* 更新任务组文件大小
*/
void updateFileSize() {
if (isNeedLoadFileSize) {
mTaskEntity.getEntity().setFileSize(mTotalLen);
mTaskEntity.getEntity().update();
mGTEntity.getEntity().setFileSize(mTotalLen);
mGTEntity.getEntity().update();
}
}
@ -170,7 +187,7 @@ public abstract class AbsGroupUtil implements IUtil {
* @param url 子任务下载地址
*/
public void cancelSubTask(String url) {
List<String> urls = mTaskEntity.entity.getUrls();
List<String> urls = mGTEntity.entity.getUrls();
if (urls != null && !urls.isEmpty() && urls.contains(url)) {
urls.remove(url);
DownloadTaskEntity det =
@ -183,7 +200,7 @@ public abstract class AbsGroupUtil implements IUtil {
mListener.onCancel();
}
}
mTaskEntity.update();
mGTEntity.update();
}
Downloader d = getDownloader(url, false);
if (d != null) {
@ -254,7 +271,7 @@ public abstract class AbsGroupUtil implements IUtil {
}
}
delDownloadInfo();
mTaskEntity.deleteData();
mGTEntity.deleteData();
}
public void onCancel() {
@ -266,20 +283,20 @@ public abstract class AbsGroupUtil implements IUtil {
*/
private void delDownloadInfo() {
List<DownloadTaskEntity> tasks =
DbEntity.findDatas(DownloadTaskEntity.class, "groupName=?", mTaskEntity.key);
DbEntity.findDatas(DownloadTaskEntity.class, "groupName=?", mGTEntity.key);
if (tasks != null && !tasks.isEmpty()) {
for (DownloadTaskEntity taskEntity : tasks) {
CommonUtil.delDownloadTaskConfig(mTaskEntity.removeFile, taskEntity);
CommonUtil.delDownloadTaskConfig(mGTEntity.removeFile, taskEntity);
}
}
File dir = new File(mTaskEntity.getEntity().getDirPath());
if (mTaskEntity.removeFile) {
File dir = new File(mGTEntity.getEntity().getDirPath());
if (mGTEntity.removeFile) {
if (dir.exists()) {
dir.delete();
}
} else {
if (!mTaskEntity.getEntity().isComplete()) {
if (!mGTEntity.getEntity().isComplete()) {
dir.delete();
}
}
@ -387,30 +404,34 @@ public abstract class AbsGroupUtil implements IUtil {
DownloadTaskEntity taskEntity = mTasksMap.get(entity.getUrl());
if (taskEntity != null) {
taskEntity.entity = entity;
//ftp登录的
if (getTaskType() == FTP_DIR) {
taskEntity.urlEntity = createFtpUrlEntity(entity);
}
mTasksMap.put(entity.getUrl(), taskEntity);
return taskEntity;
}
taskEntity = new DownloadTaskEntity();
taskEntity.entity = entity;
taskEntity.headers = mTaskEntity.headers;
taskEntity.requestEnum = mTaskEntity.requestEnum;
taskEntity.redirectUrlKey = mTaskEntity.redirectUrlKey;
taskEntity.removeFile = mTaskEntity.removeFile;
taskEntity.groupName = mTaskEntity.key;
taskEntity.headers = mGTEntity.headers;
taskEntity.requestEnum = mGTEntity.requestEnum;
taskEntity.redirectUrlKey = mGTEntity.redirectUrlKey;
taskEntity.removeFile = mGTEntity.removeFile;
taskEntity.groupName = mGTEntity.key;
taskEntity.isGroupTask = true;
taskEntity.requestType = mTaskEntity.requestType;
//ftp登录的
taskEntity.requestType = mGTEntity.requestType;
taskEntity.key = entity.getDownloadPath();
if (getTaskType() == FTP_DIR) {
taskEntity.urlEntity = createFtpUrlEntity(entity);
}
taskEntity.save();
mTasksMap.put(entity.getUrl(), taskEntity);
return taskEntity;
}
private FtpUrlEntity createFtpUrlEntity(DownloadEntity entity) {
FtpUrlEntity urlEntity = CommonUtil.getFtpUrlInfo(entity.getUrl());
urlEntity.validAddr = mTaskEntity.urlEntity.validAddr;
FtpUrlEntity urlEntity = mGTEntity.urlEntity.clone();
urlEntity.url = entity.getUrl();
urlEntity.remotePath = CommonUtil.getRemotePath(entity.getUrl());
return urlEntity;
}

@ -43,6 +43,10 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
mInfoPool = Executors.newCachedThreadPool();
}
@Override int getTaskType() {
return HTTP_GROUP;
}
@Override public void onCancel() {
super.onCancel();
if (!mInfoPool.isShutdown()) {
@ -98,7 +102,7 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
createChildDownload(te);
}
mInitNum++;
if (mInitNum + mInitFailNum >= mTaskEntity.getEntity().getSubTask().size()
if (mInitNum + mInitFailNum >= mGTEntity.getEntity().getSubTask().size()
|| !isNeedLoadFileSize) {
startRunningFlow();
updateFileSize();
@ -121,7 +125,7 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
if (mActualTaskNum < 0) mActualTaskNum = 0;
}
failNum++;
if (mInitNum + mInitFailNum >= mTaskEntity.getEntity().getSubTask().size()
if (mInitNum + mInitFailNum >= mGTEntity.getEntity().getSubTask().size()
|| !isNeedLoadFileSize) {
startRunningFlow();
updateFileSize();

@ -31,27 +31,31 @@ public class FtpDirDownloadUtil extends AbsGroupUtil {
super(listener, taskEntity);
}
@Override int getTaskType() {
return FTP_DIR;
}
@Override protected void onStart() {
super.onStart();
if (mTaskEntity.getEntity().getFileSize() > 1) {
if (mGTEntity.getEntity().getFileSize() > 1) {
startDownload();
} else {
new FtpDirInfoThread(mTaskEntity, new OnFileInfoCallback() {
new FtpDirInfoThread(mGTEntity, new OnFileInfoCallback() {
@Override public void onComplete(String url, int code) {
if (code >= 200 && code < 300) {
for (DownloadEntity entity : mTaskEntity.entity.getSubTask()) {
for (DownloadEntity entity : mGTEntity.entity.getSubTask()) {
mExeMap.put(entity.getUrl(), createChildDownloadTask(entity));
}
mActualTaskNum = mTaskEntity.entity.getSubTask().size();
mActualTaskNum = mGTEntity.entity.getSubTask().size();
mGroupSize = mActualTaskNum;
mTotalLen = mTaskEntity.entity.getFileSize();
mTotalLen = mGTEntity.entity.getFileSize();
startDownload();
}
}
@Override public void onFail(String url, String errorMsg, boolean needRetry) {
mListener.onFail(needRetry);
ErrorHelp.saveError("FTP_DIR", mTaskEntity.getEntity(), "", errorMsg);
ErrorHelp.saveError("FTP_DIR", mGTEntity.getEntity(), "", errorMsg);
}
}).start();
}

@ -37,7 +37,6 @@ class FtpDirInfoThread extends AbsFtpInfoThread<DownloadGroupEntity, DownloadGro
}
@Override protected String setRemotePath() {
String url = mEntity.getKey();
return mTaskEntity.urlEntity.remotePath;
}
@ -55,8 +54,7 @@ class FtpDirInfoThread extends AbsFtpInfoThread<DownloadGroupEntity, DownloadGro
private void addEntity(String remotePath, FTPFile ftpFile) {
final FtpUrlEntity urlEntity = mTaskEntity.urlEntity;
DownloadEntity entity = new DownloadEntity();
entity.setUrl(
urlEntity.protocol + "://" + urlEntity.hostName + ":" + urlEntity.port + remotePath);
entity.setUrl(urlEntity.protocol + "://" + urlEntity.hostName + ":" + urlEntity.port + remotePath);
entity.setDownloadPath(mEntity.getDirPath() + "/" + remotePath);
int lastIndex = remotePath.lastIndexOf("/");
String fileName = lastIndex < 0 ? CommonUtil.keyToHashKey(remotePath)

@ -109,6 +109,23 @@ public class CommonUtil {
return entity;
}
/**
* 通过url获取FTP文件的remotePath
*
* @return remotePath如果没有找到返回""
*/
public static String getRemotePath(String url) {
String remotePath = null;
String regex = Regular.REG_FTP_URL;
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(url);
if (m.find() && m.groupCount() > 0) {
return TextUtils.isEmpty(m.group(4)) ? "" : "/" + m.group(4);
}
ALog.w(TAG, "链接【" + url + "】没有找到remotePath");
return "";
}
/**
* 转换Url
*

@ -37,8 +37,8 @@ import java.io.File;
public class FtpDownloadActivity extends BaseActivity<ActivityFtpDownloadBinding> {
//private final String URL = "ftp://192.168.1.9:21/下载/AriaPrj.zip";
//private final String URL = "ftp://192.168.1.9:21/下载/[电影天堂www.dy2018.com]赛车总动员3BD中英双字.mp4";
//private final String URL = "ftp://d:d@dygodj8.com:12311/[电影天堂www.dy2018.com]光辉岁月BD韩语中字.rmvb";
private final String URL = "ftp://172.18.104.64:21/upload/成都.mp3";
private final String URL = "ftp://j:j@g.dygod18.com:7978/江湖告急BD国粤双语中字[电影天堂www.dy2018.com].mkv";
//private final String URL = "ftp://172.18.104.64:21/upload/测试/成都.mp3";
@Override protected void init(Bundle savedInstanceState) {
super.init(savedInstanceState);
@ -60,8 +60,8 @@ public class FtpDownloadActivity extends BaseActivity<ActivityFtpDownloadBinding
switch (view.getId()) {
case R.id.start:
Aria.download(this).loadFtp(URL, true)
//.charSet("GBK")
.login("lao", "123456")
.charSet("GBK")
//.login("lao", "123456")
.setDownloadPath("/mnt/sdcard/").start();
break;
case R.id.stop:

@ -35,7 +35,7 @@ import com.arialyy.simple.widget.SubStateLinearLayout;
* Created by Aria.Lao on 2017/7/6.
*/
public class FTPDirDownloadActivity extends BaseActivity<ActivityDownloadGroupBinding> {
private static final String dir = "ftp://172.18.104.64:21/haha/";
private static final String dir = "ftp://172.18.104.64:21/upload/测试";
@Bind(R.id.child_list) SubStateLinearLayout mChildList;

Loading…
Cancel
Save