From 665cc4886776ed0250a4aed62ca33f4a2c97b698 Mon Sep 17 00:00:00 2001 From: AriaLyy <511455842@qq.com> Date: Tue, 25 Jul 2017 18:29:24 +0800 Subject: [PATCH] =?UTF-8?q?ftp=E4=B8=8B=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../aria/core/download/DownloadGroupTask.java | 2 +- .../aria/core/download/DownloadTask.java | 15 +- .../aria/core/download/FtpDownloadTarget.java | 45 ++- .../download/downloader/AbsThreadTask.java | 195 ++++++++++++ .../downloader/ChildThreadConfigEntity.java | 24 -- .../downloader/{http => }/ConnectionHelp.java | 2 +- .../{http => }/DownloadGroupUtil.java | 15 +- .../downloader/{http => }/Downloader.java | 74 +++-- .../downloader/FtpFileInfoThread.java | 122 ++++++++ .../download/downloader/FtpThreadTask.java | 134 ++++++++ ...nfoThread.java => HttpFileInfoThread.java} | 24 +- .../download/downloader/HttpThreadTask.java | 122 ++++++++ .../downloader/OnFileInfoCallback.java | 17 + .../{http => }/SimpleDownloadUtil.java | 49 ++- .../download/downloader/StateConstance.java | 36 +-- .../download/downloader/SubThreadConfig.java | 24 ++ .../downloader/ftp/FtpDownloadUtil.java | 93 ------ .../downloader/ftp/FtpThreadTask.java | 281 ----------------- .../downloader/http/HttpThreadTask.java | 291 ------------------ .../arialyy/aria/core/inf/AbsTaskEntity.java | 5 + .../arialyy/aria/core/upload/UploadUtil.java | 4 +- .../com/arialyy/aria/util/CommonUtil.java | 13 + app/src/main/AndroidManifest.xml | 1 + app/src/main/assets/aria_config.xml | 2 +- .../java/com/arialyy/simple/MainActivity.java | 6 +- .../simple/download/FtpDownloadActivity.java | 106 +++++++ .../download/group/DownloadGroupActivity.java | 3 - .../main/res/layout/activity_ftp_download.xml | 36 +++ app/src/main/res/layout/activity_main.xml | 8 + .../aria/core/upload/UploadTaskEntity.java | 1 - 30 files changed, 948 insertions(+), 802 deletions(-) create mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsThreadTask.java delete mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/downloader/ChildThreadConfigEntity.java rename Aria/src/main/java/com/arialyy/aria/core/download/downloader/{http => }/ConnectionHelp.java (98%) rename Aria/src/main/java/com/arialyy/aria/core/download/downloader/{http => }/DownloadGroupUtil.java (95%) rename Aria/src/main/java/com/arialyy/aria/core/download/downloader/{http => }/Downloader.java (87%) create mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpFileInfoThread.java create mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpThreadTask.java rename Aria/src/main/java/com/arialyy/aria/core/download/downloader/{http/FileInfoThread.java => HttpFileInfoThread.java} (91%) create mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java create mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/downloader/OnFileInfoCallback.java rename Aria/src/main/java/com/arialyy/aria/core/download/downloader/{http => }/SimpleDownloadUtil.java (66%) create mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/downloader/SubThreadConfig.java delete mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/downloader/ftp/FtpDownloadUtil.java delete mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/downloader/ftp/FtpThreadTask.java delete mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/downloader/http/HttpThreadTask.java create mode 100644 app/src/main/java/com/arialyy/simple/download/FtpDownloadActivity.java create mode 100644 app/src/main/res/layout/activity_ftp_download.xml diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java index 361c8e46..6c668ad2 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java @@ -17,7 +17,7 @@ package com.arialyy.aria.core.download; import android.os.Handler; import com.arialyy.aria.core.AriaManager; -import com.arialyy.aria.core.download.downloader.http.DownloadGroupUtil; +import com.arialyy.aria.core.download.downloader.DownloadGroupUtil; import com.arialyy.aria.core.download.downloader.IDownloadUtil; import com.arialyy.aria.core.inf.AbsGroupTask; import com.arialyy.aria.core.scheduler.ISchedulers; diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTask.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTask.java index 2dcf3420..e43b0eeb 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTask.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTask.java @@ -19,11 +19,9 @@ package com.arialyy.aria.core.download; import android.os.Handler; import android.util.Log; import com.arialyy.aria.core.AriaManager; -import com.arialyy.aria.core.download.downloader.ftp.FtpDownloadUtil; import com.arialyy.aria.core.download.downloader.IDownloadUtil; -import com.arialyy.aria.core.download.downloader.http.SimpleDownloadUtil; +import com.arialyy.aria.core.download.downloader.SimpleDownloadUtil; import com.arialyy.aria.core.inf.AbsNormalTask; -import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.scheduler.ISchedulers; import java.io.File; @@ -43,11 +41,12 @@ public class DownloadTask extends AbsNormalTask { mOutHandler = outHandler; mContext = AriaManager.APP; mListener = new DownloadListener(this, mOutHandler); - if (taskEntity.downloadType == AbsTaskEntity.HTTP) { - mUtil = new SimpleDownloadUtil(taskEntity, mListener); - }else if (taskEntity.downloadType == AbsTaskEntity.FTP){ - mUtil = new FtpDownloadUtil(taskEntity, mListener); - } + mUtil = new SimpleDownloadUtil(taskEntity, mListener); + //if (taskEntity.downloadType == AbsTaskEntity.HTTP) { + // mUtil = new SimpleDownloadUtil(taskEntity, mListener); + //}else if (taskEntity.downloadType == AbsTaskEntity.FTP){ + // mUtil = new FtpDownloadUtil(taskEntity, mListener); + //} } /** diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java index 52b46fca..1f170891 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java @@ -15,10 +15,13 @@ */ 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.CommonUtil; +import java.io.File; +import java.nio.charset.Charset; /** * Created by lyy on 2016/12/5. @@ -32,7 +35,7 @@ public class FtpDownloadTarget extends DownloadTarget { * @param port ftp端口号 */ FtpDownloadTarget(String serverIp, String port, String filePath, String targetName) { - this(serverIp + ":" + port + "/" + filePath, targetName); + this("ftp://" + serverIp + ":" + port + "/" + filePath, targetName); } /** @@ -46,6 +49,46 @@ public class FtpDownloadTarget extends DownloadTarget { mEntity.setFileName(url.substring(lastIndex + 1, url.length())); } + /** + * 设置文件保存文件夹路径 + * 关于文件名: + * 1、如果保存路径是该文件的保存路径,如:/mnt/sdcard/file.zip,则使用路径中的文件名file.zip + * 2、如果保存路径是文件夹路径,如:/mnt/sdcard/,则使用FTP服务器该文件的文件名 + * + * @param downloadPath 路径必须为文件路径,不能为文件夹路径 + */ + @Override public FtpDownloadTarget setDownloadPath(@NonNull String downloadPath) { + if (TextUtils.isEmpty(downloadPath)) { + throw new IllegalArgumentException("文件保持路径不能为null"); + } + File file = new File(downloadPath); + if (file.isDirectory()) { + downloadPath += mEntity.getFileName(); + } + if (!downloadPath.equals(mEntity.getDownloadPath())) { + File oldFile = new File(mEntity.getDownloadPath()); + File newFile = new File(downloadPath); + if (TextUtils.isEmpty(mEntity.getDownloadPath()) || oldFile.renameTo(newFile)) { + mEntity.setDownloadPath(downloadPath); + mEntity.setFileName(newFile.getName()); + mTaskEntity.key = downloadPath; + mEntity.update(); + mTaskEntity.update(); + CommonUtil.renameDownloadConfig(oldFile.getName(), newFile.getName()); + } + } + return this; + } + + /** + * 设置字符编码 + */ + public FtpDownloadTarget charSet(String charSet) { + if (TextUtils.isEmpty(charSet)) return this; + mTaskEntity.charSet = charSet; + return this; + } + /** * ftp 用户登录信息 * diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsThreadTask.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsThreadTask.java new file mode 100644 index 00000000..c3710eaa --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsThreadTask.java @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.arialyy.aria.core.download.downloader; + +import android.os.Build; +import android.text.TextUtils; +import android.util.Log; +import com.arialyy.aria.core.AriaManager; +import com.arialyy.aria.core.download.DownloadEntity; +import com.arialyy.aria.core.download.DownloadTaskEntity; +import com.arialyy.aria.util.CommonUtil; +import java.io.File; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.Properties; + +/** + * Created by lyy on 2017/1/18. + * 下载线程 + */ +abstract class AbsThreadTask implements Runnable { + private final String TAG = "AbsThreadTask"; + long mChildCurrentLocation = 0, mSleepTime = 0; + int mBufSize; + String mConfigFPath; + SubThreadConfig mConfig; + IDownloadListener mListener; + StateConstance STATE; + DownloadEntity mEntity; + DownloadTaskEntity mTaskEntity; + + AbsThreadTask(StateConstance constance, IDownloadListener listener, + SubThreadConfig downloadInfo) { + AriaManager manager = AriaManager.getInstance(AriaManager.APP); + STATE = constance; + STATE.CONNECT_TIME_OUT = manager.getDownloadConfig().getConnectTimeOut(); + STATE.READ_TIME_OUT = manager.getDownloadConfig().getIOTimeOut(); + mListener = listener; + mConfig = downloadInfo; + mTaskEntity = mConfig.DOWNLOAD_TASK_ENTITY; + mEntity = mTaskEntity.getEntity(); + if (mConfig.IS_SUPPORT_BREAK_POINT) { + mConfigFPath = downloadInfo.CONFIG_FILE_PATH; + } + mBufSize = manager.getDownloadConfig().getBuffSize(); + setMaxSpeed(AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMsxSpeed()); + } + + void setMaxSpeed(double maxSpeed) { + if (-0.9999 < maxSpeed && maxSpeed < 0.00001) { + mSleepTime = 0; + } else { + BigDecimal db = new BigDecimal( + ((mBufSize / 1024) * (filterVersion() ? 1 : STATE.THREAD_NUM) / maxSpeed) * 1000); + mSleepTime = db.setScale(0, BigDecimal.ROUND_HALF_UP).longValue(); + } + } + + private boolean filterVersion() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; + } + + /** + * 停止下载 + */ + void stop() { + synchronized (AriaManager.LOCK) { + try { + if (mConfig.IS_SUPPORT_BREAK_POINT) { + STATE.STOP_NUM++; + Log.d(TAG, "任务【" + + mConfig.TEMP_FILE.getName() + + "】thread__" + + mConfig.THREAD_ID + + "__停止, stop location ==> " + + mChildCurrentLocation); + writeConfig(false, mChildCurrentLocation); + if (STATE.isStop()) { + Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已停止"); + STATE.isDownloading = false; + mListener.onStop(STATE.CURRENT_LOCATION); + } + } else { + Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已停止"); + STATE.isDownloading = false; + mListener.onStop(STATE.CURRENT_LOCATION); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * 下载中 + */ + void progress(long len) { + synchronized (AriaManager.LOCK) { + mChildCurrentLocation += len; + STATE.CURRENT_LOCATION += len; + } + } + + /** + * 取消下载 + */ + void cancel() { + synchronized (AriaManager.LOCK) { + if (mConfig.IS_SUPPORT_BREAK_POINT) { + STATE.CANCEL_NUM++; + Log.d(TAG, + "任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__取消下载"); + if (STATE.isCancel()) { + File configFile = new File(mConfigFPath); + if (configFile.exists()) { + configFile.delete(); + } + if (mConfig.TEMP_FILE.exists()) { + mConfig.TEMP_FILE.delete(); + } + Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已取消"); + STATE.isDownloading = false; + mListener.onCancel(); + } + } else { + Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已取消"); + STATE.isDownloading = false; + mListener.onCancel(); + } + } + } + + /** + * 下载失败 + */ + void failDownload(long currentLocation, String msg, Exception ex) { + synchronized (AriaManager.LOCK) { + try { + STATE.FAIL_NUM++; + STATE.isDownloading = false; + STATE.isStop = true; + if (ex != null) { + Log.e(TAG, msg + "\n" + CommonUtil.getPrintException(ex)); + } + if (mConfig.IS_SUPPORT_BREAK_POINT) { + writeConfig(false, currentLocation); + if (STATE.isFail()) { + Log.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】下载失败"); + mListener.onFail(); + } + } else { + Log.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】下载失败"); + mListener.onFail(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * 将记录写入到配置文件 + */ + void writeConfig(boolean isComplete, long record) throws IOException { + synchronized (AriaManager.LOCK) { + String key = null, value = null; + if (0 < record && record < mConfig.END_LOCATION) { + key = mConfig.TEMP_FILE.getName() + "_record_" + mConfig.THREAD_ID; + value = String.valueOf(record); + } else if (record >= mConfig.END_LOCATION || isComplete) { + key = mConfig.TEMP_FILE.getName() + "_state_" + mConfig.THREAD_ID; + value = "1"; + } + if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) { + File configFile = new File(mConfigFPath); + Properties pro = CommonUtil.loadConfig(configFile); + pro.setProperty(key, value); + CommonUtil.saveConfig(configFile, pro); + } + } + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ChildThreadConfigEntity.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ChildThreadConfigEntity.java deleted file mode 100644 index 2563205b..00000000 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ChildThreadConfigEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.arialyy.aria.core.download.downloader; - -import com.arialyy.aria.core.download.DownloadTaskEntity; -import java.io.File; - -/** - * 子线程下载信息类 - */ -public class ChildThreadConfigEntity { - //线程Id - public int THREAD_ID; - //下载文件大小 - public long FILE_SIZE; - //子线程启动下载位置 - public long START_LOCATION; - //子线程结束下载位置 - public long END_LOCATION; - //下载路径 - public File TEMP_FILE; - public String DOWNLOAD_URL; - public String CONFIG_FILE_PATH; - public DownloadTaskEntity DOWNLOAD_TASK_ENTITY; - public boolean IS_SUPPORT_BREAK_POINT = true; -} \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/http/ConnectionHelp.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java similarity index 98% rename from Aria/src/main/java/com/arialyy/aria/core/download/downloader/http/ConnectionHelp.java rename to Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java index 4970e5cc..028db87c 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/http/ConnectionHelp.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.arialyy.aria.core.download.downloader.http; +package com.arialyy.aria.core.download.downloader; import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.util.SSLContextUtil; diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/http/DownloadGroupUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java similarity index 95% rename from Aria/src/main/java/com/arialyy/aria/core/download/downloader/http/DownloadGroupUtil.java rename to Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java index 66062d32..7fe1ad68 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/http/DownloadGroupUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java @@ -13,15 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.arialyy.aria.core.download.downloader.http; +package com.arialyy.aria.core.download.downloader; import android.util.SparseArray; import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadGroupTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity; -import com.arialyy.aria.core.download.downloader.IDownloadGroupListener; -import com.arialyy.aria.core.download.downloader.IDownloadListener; -import com.arialyy.aria.core.download.downloader.IDownloadUtil; import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.util.CommonUtil; @@ -78,7 +75,7 @@ public class DownloadGroupUtil implements IDownloadUtil { /** * 文件信息回调组 */ - private SparseArray mFileInfoCallbacks = new SparseArray<>(); + private SparseArray mFileInfoCallbacks = new SparseArray<>(); /** * 该任务组对应的所有任务 */ @@ -214,11 +211,11 @@ public class DownloadGroupUtil implements IDownloadUtil { /** * 创建文件信息获取线程 */ - private FileInfoThread createFileInfoThread(DownloadTaskEntity taskEntity) { - FileInfoThread.OnFileInfoCallback callback = mFileInfoCallbacks.get(taskEntity.hashCode()); + private HttpFileInfoThread createFileInfoThread(DownloadTaskEntity taskEntity) { + OnFileInfoCallback callback = mFileInfoCallbacks.get(taskEntity.hashCode()); if (callback == null) { - callback = new FileInfoThread.OnFileInfoCallback() { + callback = new OnFileInfoCallback() { int failNum = 0; @Override public void onComplete(String url, int code) { @@ -255,7 +252,7 @@ public class DownloadGroupUtil implements IDownloadUtil { } }; } - return new FileInfoThread(taskEntity, callback); + return new HttpFileInfoThread(taskEntity, callback); } private void closeTimer(boolean isRunning) { diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/http/Downloader.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java similarity index 87% rename from Aria/src/main/java/com/arialyy/aria/core/download/downloader/http/Downloader.java rename to Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java index a41cecba..f3821aa1 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/http/Downloader.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.arialyy.aria.core.download.downloader.http; +package com.arialyy.aria.core.download.downloader; import android.content.Context; import android.util.Log; @@ -21,10 +21,7 @@ import android.util.SparseArray; import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadTaskEntity; -import com.arialyy.aria.core.download.downloader.ChildThreadConfigEntity; -import com.arialyy.aria.core.download.downloader.IDownloadListener; -import com.arialyy.aria.core.download.downloader.IDownloadUtil; -import com.arialyy.aria.core.download.downloader.StateConstance; +import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.util.BufferedRandomAccessFile; import com.arialyy.aria.util.CommonUtil; @@ -53,7 +50,7 @@ class Downloader implements Runnable, IDownloadUtil { private boolean isNewTask = true; private int mThreadNum, mRealThreadNum; private StateConstance mConstance; - private SparseArray mTask = new SparseArray<>(); + private SparseArray mTask = new SparseArray<>(); /** * 小于1m的文件不启用多线程 @@ -69,10 +66,9 @@ class Downloader implements Runnable, IDownloadUtil { mConstance = new StateConstance(); } - @Override - public void setMaxSpeed(double maxSpeed) { + @Override public void setMaxSpeed(double maxSpeed) { for (int i = 0; i < mThreadNum; i++) { - HttpThreadTask task = (HttpThreadTask) mTask.get(i); + AbsThreadTask task = mTask.get(i); if (task != null) { task.setMaxSpeed(maxSpeed); } @@ -155,7 +151,7 @@ class Downloader implements Runnable, IDownloadUtil { mFixedThreadPool.shutdown(); } for (int i = 0; i < mThreadNum; i++) { - HttpThreadTask task = (HttpThreadTask) mTask.get(i); + AbsThreadTask task = mTask.get(i); if (task != null) { task.cancel(); } @@ -172,7 +168,7 @@ class Downloader implements Runnable, IDownloadUtil { mFixedThreadPool.shutdown(); } for (int i = 0; i < mThreadNum; i++) { - HttpThreadTask task = (HttpThreadTask) mTask.get(i); + AbsThreadTask task = mTask.get(i); if (task != null) { task.stop(); } @@ -285,18 +281,19 @@ class Downloader implements Runnable, IDownloadUtil { * 创建单线程任务 */ private void addSingleTask(int i, long startL, long endL, long fileLength) { - ChildThreadConfigEntity entity = new ChildThreadConfigEntity(); - entity.FILE_SIZE = fileLength; - entity.DOWNLOAD_URL = + SubThreadConfig config = new SubThreadConfig(); + config.FILE_SIZE = fileLength; + config.DOWNLOAD_URL = mEntity.isRedirect() ? mEntity.getRedirectUrl() : mEntity.getDownloadUrl(); - entity.TEMP_FILE = mTempFile; - entity.THREAD_ID = i; - entity.START_LOCATION = startL; - entity.END_LOCATION = endL; - entity.CONFIG_FILE_PATH = mConfigFile.getPath(); - entity.IS_SUPPORT_BREAK_POINT = mTaskEntity.isSupportBP; - entity.DOWNLOAD_TASK_ENTITY = mTaskEntity; - HttpThreadTask task = new HttpThreadTask(mConstance, mListener, entity); + config.TEMP_FILE = mTempFile; + config.THREAD_ID = i; + config.START_LOCATION = startL; + config.END_LOCATION = endL; + config.CONFIG_FILE_PATH = mConfigFile.getPath(); + config.IS_SUPPORT_BREAK_POINT = mTaskEntity.isSupportBP; + config.DOWNLOAD_TASK_ENTITY = mTaskEntity; + AbsThreadTask task = createThreadTask(config); + if (task == null) return; mTask.put(i, task); } @@ -396,25 +393,36 @@ class Downloader implements Runnable, IDownloadUtil { * 处理不支持断点的下载 */ private void handleNoSupportBreakpointDownload() { - ChildThreadConfigEntity entity = new ChildThreadConfigEntity(); + SubThreadConfig config = new SubThreadConfig(); long len = mEntity.getFileSize(); - entity.FILE_SIZE = len; - entity.DOWNLOAD_URL = + config.FILE_SIZE = len; + config.DOWNLOAD_URL = mEntity.isRedirect() ? mEntity.getRedirectUrl() : mEntity.getDownloadUrl(); - entity.TEMP_FILE = mTempFile; - entity.THREAD_ID = 0; - entity.START_LOCATION = 0; - entity.END_LOCATION = entity.FILE_SIZE; - entity.CONFIG_FILE_PATH = mConfigFile.getPath(); - entity.IS_SUPPORT_BREAK_POINT = mTaskEntity.isSupportBP; - entity.DOWNLOAD_TASK_ENTITY = mTaskEntity; - HttpThreadTask task = new HttpThreadTask(mConstance, mListener, entity); + config.TEMP_FILE = mTempFile; + config.THREAD_ID = 0; + config.START_LOCATION = 0; + config.END_LOCATION = config.FILE_SIZE; + config.CONFIG_FILE_PATH = mConfigFile.getPath(); + config.IS_SUPPORT_BREAK_POINT = mTaskEntity.isSupportBP; + config.DOWNLOAD_TASK_ENTITY = mTaskEntity; + AbsThreadTask task = createThreadTask(config); + if (task == null) return; mTask.put(0, task); mFixedThreadPool.execute(task); mListener.onPostPre(len); mListener.onStart(0); } + private AbsThreadTask createThreadTask(SubThreadConfig config) { + switch (mTaskEntity.downloadType) { + case AbsTaskEntity.FTP: + return new FtpThreadTask(mConstance, mListener, config); + case AbsTaskEntity.HTTP: + return new HttpThreadTask(mConstance, mListener, config); + } + return null; + } + private void failDownload(String errorMsg) { closeTimer(); Log.e(TAG, errorMsg); diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpFileInfoThread.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpFileInfoThread.java new file mode 100644 index 00000000..e606fb81 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpFileInfoThread.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.arialyy.aria.core.download.downloader; + +import android.text.TextUtils; +import android.util.Log; +import com.arialyy.aria.core.AriaManager; +import com.arialyy.aria.core.download.DownloadEntity; +import com.arialyy.aria.core.download.DownloadTaskEntity; +import com.arialyy.aria.util.CommonUtil; +import java.io.IOException; +import org.apache.commons.net.ftp.FTP; +import org.apache.commons.net.ftp.FTPClient; +import org.apache.commons.net.ftp.FTPFile; +import org.apache.commons.net.ftp.FTPReply; + +/** + * Created by Aria.Lao on 2017/7/25. + * 获取ftp文件信息 + */ +class FtpFileInfoThread implements Runnable { + + private final String TAG = "HttpFileInfoThread"; + private DownloadEntity mEntity; + private DownloadTaskEntity mTaskEntity; + private int mConnectTimeOut; + private OnFileInfoCallback mCallback; + + FtpFileInfoThread(DownloadTaskEntity taskEntity, OnFileInfoCallback callback) { + this.mTaskEntity = taskEntity; + mEntity = taskEntity.getEntity(); + mConnectTimeOut = + AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getConnectTimeOut(); + mCallback = callback; + } + + @Override public void run() { + FTPClient client = null; + try { + client = new FTPClient(); + //ip和端口 + String[] temp = mEntity.getDownloadUrl().split("/"); + String[] pp = temp[2].split(":"); + //String dir = temp[temp.length - 2]; + String fileName = temp[temp.length - 1]; + client.connect(pp[0], Integer.parseInt(pp[1])); + if (!TextUtils.isEmpty(mTaskEntity.account)) { + client.login(mTaskEntity.userName, mTaskEntity.userPw); + } else { + client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account); + } + int reply = client.getReplyCode(); + if (!FTPReply.isPositiveCompletion(reply)) { + client.disconnect(); + failDownload("无法连接到ftp服务器,错误码为:" + reply); + return; + } + client.setDataTimeout(mConnectTimeOut); + client.enterLocalPassiveMode(); + client.setFileType(FTP.BINARY_FILE_TYPE); + FTPFile[] files = + client.listFiles(CommonUtil.strCharSetConvert(fileName, mTaskEntity.charSet)); + long size = getFileSize(files, client, fileName); + mEntity.setFileSize(size); + mTaskEntity.code = reply; + mEntity.update(); + mTaskEntity.update(); + mCallback.onComplete(mEntity.getDownloadUrl(), reply); + } catch (IOException e) { + failDownload(e.getMessage()); + } finally { + if (client != null) { + try { + client.logout(); + client.disconnect(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + /** + * 遍历FTP服务器上对应文件或文件夹大小 + * + * @throws IOException + */ + private long getFileSize(FTPFile[] files, FTPClient client, String dirName) throws IOException { + long size = 0; + String path = dirName + "/"; + for (FTPFile file : files) { + if (file.isFile()) { + size += file.getSize(); + } else { + size += getFileSize(client.listFiles( + CommonUtil.strCharSetConvert(path + file.getName(), mTaskEntity.charSet)), client, + path + file.getName()); + } + } + return size; + } + + private void failDownload(String errorMsg) { + Log.e(TAG, errorMsg); + if (mCallback != null) { + mCallback.onFail(mEntity.getDownloadUrl(), errorMsg); + } + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpThreadTask.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpThreadTask.java new file mode 100644 index 00000000..833f3799 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpThreadTask.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.arialyy.aria.core.download.downloader; + +import android.text.TextUtils; +import android.util.Log; +import com.arialyy.aria.util.BufferedRandomAccessFile; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Timer; +import java.util.TimerTask; +import org.apache.commons.net.ftp.FTP; +import org.apache.commons.net.ftp.FTPClient; +import org.apache.commons.net.ftp.FTPFile; +import org.apache.commons.net.ftp.FTPReply; + +/** + * Created by Aria.Lao on 2017/7/24. + * Ftp下载任务 + */ +class FtpThreadTask extends AbsThreadTask { + private final String TAG = "FtpThreadTask"; + + FtpThreadTask(StateConstance constance, IDownloadListener listener, + SubThreadConfig downloadInfo) { + super(constance, listener, downloadInfo); + } + + @Override public void run() { + FTPClient client = null; + InputStream is = null; + BufferedRandomAccessFile file = null; + try { + Log.d(TAG, "任务【" + + mConfig.TEMP_FILE.getName() + + "】线程__" + + mConfig.THREAD_ID + + "__开始下载【开始位置 : " + + mConfig.START_LOCATION + + ",结束位置:" + + mConfig.END_LOCATION + + "】"); + client = new FTPClient(); + //ip和端口 + String[] temp = mEntity.getDownloadUrl().split("/"); + String[] pp = temp[2].split(":"); + //String dir = temp[temp.length - 2]; + String fileName = temp[temp.length - 1]; + client.connect(pp[0], Integer.parseInt(pp[1])); + if (!TextUtils.isEmpty(mTaskEntity.account)) { + client.login(mTaskEntity.userName, mTaskEntity.userPw); + } else { + client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account); + } + int reply = client.getReplyCode(); + if (!FTPReply.isPositiveCompletion(reply)) { + client.disconnect(); + failDownload(STATE.CURRENT_LOCATION, "无法连接到ftp服务器,错误码为:" + reply, null); + return; + } + client.setDataTimeout(STATE.READ_TIME_OUT); + client.enterLocalPassiveMode(); + client.setFileType(FTP.BINARY_FILE_TYPE); + client.setRestartOffset(mConfig.START_LOCATION); + is = client.retrieveFileStream(fileName); + file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize); + file.seek(mConfig.START_LOCATION); + byte[] buffer = new byte[mBufSize]; + int len; + //当前子线程的下载位置 + mChildCurrentLocation = mConfig.START_LOCATION; + //TODO: 2017/7/25 隐藏问题,速度太快(20m/s)或文件太小,秒下,会出现 ftp Connection reset by peer 问题 + while ((len = is.read(buffer)) != -1) { + if (STATE.isCancel) break; + if (STATE.isStop) break; + if (mSleepTime > 0) Thread.sleep(mSleepTime); + if (mChildCurrentLocation + len >= mConfig.END_LOCATION) { + len = (int) (mConfig.END_LOCATION - mChildCurrentLocation); + file.write(buffer, 0, len); + progress(len); + break; + } else { + file.write(buffer, 0, len); + progress(len); + } + } + if (STATE.isCancel || STATE.isStop) return; + if (client.completePendingCommand()) { + Log.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】线程__" + mConfig.THREAD_ID + "__下载完毕"); + writeConfig(true, 1); + STATE.COMPLETE_THREAD_NUM++; + if (STATE.isComplete()) { + File configFile = new File(mConfigFPath); + if (configFile.exists()) { + configFile.delete(); + } + STATE.isDownloading = false; + mListener.onComplete(); + } + file.close(); + is.close(); + Log.d(TAG, "SUCCESS"); + } + } catch (IOException e) { + failDownload(mChildCurrentLocation, "下载失败【" + mConfig.DOWNLOAD_URL + "】", e); + } catch (Exception e) { + failDownload(mChildCurrentLocation, "获取流失败", e); + } finally { + try { + if (client != null && client.isConnected()) { + //client.logout(); + client.disconnect(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/http/FileInfoThread.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java similarity index 91% rename from Aria/src/main/java/com/arialyy/aria/core/download/downloader/http/FileInfoThread.java rename to Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java index 45ca5220..8fe2c54a 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/http/FileInfoThread.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java @@ -13,13 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.arialyy.aria.core.download.downloader.http; +package com.arialyy.aria.core.download.downloader; import android.text.TextUtils; import android.util.Log; import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadTaskEntity; +import com.arialyy.aria.core.download.downloader.ConnectionHelp; import com.arialyy.aria.util.CommonUtil; import java.io.IOException; import java.net.HttpURLConnection; @@ -29,30 +30,15 @@ import java.net.URLDecoder; /** * 下载文件信息获取 */ -class FileInfoThread implements Runnable { - private final String TAG = "FileInfoThread"; +class HttpFileInfoThread implements Runnable { + private final String TAG = "HttpFileInfoThread"; private DownloadEntity mEntity; private DownloadTaskEntity mTaskEntity; private int mConnectTimeOut; private OnFileInfoCallback onFileInfoListener; - interface OnFileInfoCallback { - /** - * 处理完成 - * - * @param code 状态码 - */ - void onComplete(String url, int code); - /** - * 请求失败 - * - * @param errorMsg 错误信息 - */ - void onFail(String url, String errorMsg); - } - - FileInfoThread(DownloadTaskEntity taskEntity, OnFileInfoCallback callback) { + HttpFileInfoThread(DownloadTaskEntity taskEntity, OnFileInfoCallback callback) { this.mTaskEntity = taskEntity; mEntity = taskEntity.getEntity(); mConnectTimeOut = diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java new file mode 100644 index 00000000..953e2943 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.arialyy.aria.core.download.downloader; + +import android.util.Log; +import com.arialyy.aria.util.BufferedRandomAccessFile; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; + +/** + * Created by lyy on 2017/1/18. + * 下载线程 + */ +final class HttpThreadTask extends AbsThreadTask { + private final String TAG = "HttpThreadTask"; + + HttpThreadTask(StateConstance constance, IDownloadListener listener, + SubThreadConfig downloadInfo) { + super(constance, listener, downloadInfo); + } + + @Override public void run() { + HttpURLConnection conn = null; + InputStream is = null; + BufferedRandomAccessFile file = null; + try { + URL url = new URL(mConfig.DOWNLOAD_URL); + conn = ConnectionHelp.handleConnection(url); + if (mConfig.IS_SUPPORT_BREAK_POINT) { + Log.d(TAG, "任务【" + + mConfig.TEMP_FILE.getName() + + "】线程__" + + mConfig.THREAD_ID + + "__开始下载【开始位置 : " + + mConfig.START_LOCATION + + ",结束位置:" + + mConfig.END_LOCATION + + "】"); + //在头里面请求下载开始位置和结束位置 + conn.setRequestProperty("Range", + "bytes=" + mConfig.START_LOCATION + "-" + (mConfig.END_LOCATION - 1)); + } else { + Log.w(TAG, "该下载不支持断点"); + } + conn = ConnectionHelp.setConnectParam(mConfig.DOWNLOAD_TASK_ENTITY, conn); + conn.setConnectTimeout(STATE.CONNECT_TIME_OUT); + conn.setReadTimeout(STATE.READ_TIME_OUT); //设置读取流的等待时间,必须设置该参数 + is = conn.getInputStream(); + //创建可设置位置的文件 + file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize); + //设置每条线程写入文件的位置 + file.seek(mConfig.START_LOCATION); + byte[] buffer = new byte[mBufSize]; + int len; + //当前子线程的下载位置 + mChildCurrentLocation = mConfig.START_LOCATION; + while ((len = is.read(buffer)) != -1) { + if (STATE.isCancel) break; + if (STATE.isStop) break; + if (mSleepTime > 0) Thread.sleep(mSleepTime); + file.write(buffer, 0, len); + progress(len); + } + if (STATE.isCancel || STATE.isStop) return; + //支持断点的处理 + if (mConfig.IS_SUPPORT_BREAK_POINT) { + Log.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】线程__" + mConfig.THREAD_ID + "__下载完毕"); + writeConfig(true, 1); + STATE.COMPLETE_THREAD_NUM++; + if (STATE.isComplete()) { + File configFile = new File(mConfigFPath); + if (configFile.exists()) { + configFile.delete(); + } + STATE.isDownloading = false; + mListener.onComplete(); + } + } else { + Log.i(TAG, "下载任务完成"); + STATE.isDownloading = false; + mListener.onComplete(); + } + } catch (MalformedURLException e) { + failDownload(mChildCurrentLocation, "下载链接异常", e); + } catch (IOException e) { + failDownload(mChildCurrentLocation, "下载失败【" + mConfig.DOWNLOAD_URL + "】", e); + } catch (Exception e) { + failDownload(mChildCurrentLocation, "获取流失败", e); + } finally { + try { + if (file != null) { + file.close(); + } + if (is != null) { + is.close(); + } + if (conn != null) { + conn.disconnect(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/OnFileInfoCallback.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/OnFileInfoCallback.java new file mode 100644 index 00000000..9e2071e2 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/OnFileInfoCallback.java @@ -0,0 +1,17 @@ +package com.arialyy.aria.core.download.downloader; + +interface OnFileInfoCallback { + /** + * 处理完成 + * + * @param code 状态码 + */ + void onComplete(String url, int code); + + /** + * 请求失败 + * + * @param errorMsg 错误信息 + */ + void onFail(String url, String errorMsg); +} \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/http/SimpleDownloadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/SimpleDownloadUtil.java similarity index 66% rename from Aria/src/main/java/com/arialyy/aria/core/download/downloader/http/SimpleDownloadUtil.java rename to Aria/src/main/java/com/arialyy/aria/core/download/downloader/SimpleDownloadUtil.java index 4b0b6311..15966955 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/http/SimpleDownloadUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/SimpleDownloadUtil.java @@ -14,17 +14,15 @@ * limitations under the License. */ -package com.arialyy.aria.core.download.downloader.http; +package com.arialyy.aria.core.download.downloader; -import android.text.TextUtils; import android.util.Log; import com.arialyy.aria.core.download.DownloadTaskEntity; -import com.arialyy.aria.core.download.downloader.IDownloadListener; -import com.arialyy.aria.core.download.downloader.IDownloadUtil; +import com.arialyy.aria.core.inf.AbsTaskEntity; /** * Created by lyy on 2015/8/25. - * 简单的下载工具 + * HTTP单任务下载工具 */ public class SimpleDownloadUtil implements IDownloadUtil, Runnable { private static final String TAG = "SimpleDownloadUtil"; @@ -89,18 +87,39 @@ public class SimpleDownloadUtil implements IDownloadUtil, Runnable { } @Override public void run() { - if (TextUtils.isEmpty(mTaskEntity.redirectUrl)) { - new Thread(new FileInfoThread(mTaskEntity, new FileInfoThread.OnFileInfoCallback() { - @Override public void onComplete(String url, int code) { - mDT.startDownload(); - } - - @Override public void onFail(String url, String errorMsg) { - failDownload(errorMsg); - } - })).start(); + if (mTaskEntity.getEntity().getFileSize() <= 1) { + new Thread(createInfoThread()).start(); } else { mDT.startDownload(); } } + + /** + * 通过链接类型创建不同的获取文件信息的线程 + */ + private Runnable createInfoThread() { + switch (mTaskEntity.downloadType) { + case AbsTaskEntity.FTP: + return new FtpFileInfoThread(mTaskEntity, new OnFileInfoCallback() { + @Override public void onComplete(String url, int code) { + mDT.startDownload(); + } + + @Override public void onFail(String url, String errorMsg) { + failDownload(errorMsg); + } + }); + case AbsTaskEntity.HTTP: + return new HttpFileInfoThread(mTaskEntity, new OnFileInfoCallback() { + @Override public void onComplete(String url, int code) { + mDT.startDownload(); + } + + @Override public void onFail(String url, String errorMsg) { + failDownload(errorMsg); + } + }); + } + return null; + } } \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/StateConstance.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/StateConstance.java index 7161d995..9505be5d 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/StateConstance.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/StateConstance.java @@ -19,23 +19,23 @@ package com.arialyy.aria.core.download.downloader; * Created by lyy on 2017/1/18. * 下载状态常量 */ -public class StateConstance { - public int CANCEL_NUM = 0; - public int STOP_NUM = 0; - public int FAIL_NUM = 0; - public int CONNECT_TIME_OUT; //连接超时时间 - public int READ_TIME_OUT; //流读取的超时时间 - public int COMPLETE_THREAD_NUM = 0; - public int THREAD_NUM; - public long CURRENT_LOCATION = 0; - public boolean isDownloading = false; - public boolean isCancel = false; - public boolean isStop = false; +class StateConstance { + int CANCEL_NUM = 0; + int STOP_NUM = 0; + int FAIL_NUM = 0; + int CONNECT_TIME_OUT; //连接超时时间 + int READ_TIME_OUT; //流读取的超时时间 + int COMPLETE_THREAD_NUM = 0; + int THREAD_NUM; + long CURRENT_LOCATION = 0; + boolean isDownloading = false; + boolean isCancel = false; + boolean isStop = false; - public StateConstance() { + StateConstance() { } - public void cleanState() { + void cleanState() { isCancel = false; isStop = false; isDownloading = true; @@ -48,28 +48,28 @@ public class StateConstance { /** * 所有子线程是否都已经停止下载 */ - public boolean isStop() { + boolean isStop() { return STOP_NUM == THREAD_NUM; } /** * 所有子线程是否都已经下载失败 */ - public boolean isFail() { + boolean isFail() { return FAIL_NUM == THREAD_NUM; } /** * 所有子线程是否都已经完成下载 */ - public boolean isComplete() { + boolean isComplete() { return COMPLETE_THREAD_NUM == THREAD_NUM; } /** * 所有子线程是否都已经取消下载 */ - public boolean isCancel() { + boolean isCancel() { return CANCEL_NUM == THREAD_NUM; } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/SubThreadConfig.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/SubThreadConfig.java new file mode 100644 index 00000000..aba3f53f --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/SubThreadConfig.java @@ -0,0 +1,24 @@ +package com.arialyy.aria.core.download.downloader; + +import com.arialyy.aria.core.download.DownloadTaskEntity; +import java.io.File; + +/** + * 子线程下载信息类 + */ +class SubThreadConfig { + //线程Id + int THREAD_ID; + //下载文件大小 + long FILE_SIZE; + //子线程启动下载位置 + long START_LOCATION; + //子线程结束下载位置 + long END_LOCATION; + //下载路径 + File TEMP_FILE; + String DOWNLOAD_URL; + String CONFIG_FILE_PATH; + DownloadTaskEntity DOWNLOAD_TASK_ENTITY; + boolean IS_SUPPORT_BREAK_POINT = true; +} \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ftp/FtpDownloadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ftp/FtpDownloadUtil.java deleted file mode 100644 index f01f752c..00000000 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ftp/FtpDownloadUtil.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.arialyy.aria.core.download.downloader.ftp; - -import com.arialyy.aria.core.download.DownloadEntity; -import com.arialyy.aria.core.download.DownloadTaskEntity; -import com.arialyy.aria.core.download.downloader.IDownloadListener; -import com.arialyy.aria.core.download.downloader.IDownloadUtil; -import com.arialyy.aria.util.BufferedRandomAccessFile; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import org.apache.commons.net.ftp.FTP; -import org.apache.commons.net.ftp.FTPClient; -import org.apache.commons.net.ftp.FTPFile; -import org.apache.commons.net.ftp.FTPFileEntryParser; -import org.apache.commons.net.ftp.FTPListParseEngine; -import org.apache.commons.net.ftp.FTPReply; - -/** - * Created by Aria.Lao on 2017/7/21. - */ -public class FtpDownloadUtil implements IDownloadUtil, Runnable { - - private IDownloadListener mListener; - private DownloadTaskEntity mTaskEntity; - private DownloadEntity mEntity; - - public FtpDownloadUtil(DownloadTaskEntity entity, IDownloadListener downloadListener) { - mTaskEntity = entity; - mListener = downloadListener; - mEntity = mTaskEntity.getEntity(); - } - - @Override public long getFileSize() { - return 0; - } - - @Override public long getCurrentLocation() { - return 0; - } - - @Override public boolean isDownloading() { - return false; - } - - @Override public void cancelDownload() { - - } - - @Override public void stopDownload() { - - } - - @Override public void startDownload() { - mListener.onPre(); - new Thread(this).start(); - } - - @Override public void resumeDownload() { - - } - - @Override public void setMaxSpeed(double maxSpeed) { - - } - - @Override public void run() { - - } - - private void failDownload(String msg) { - - } - - private void test() throws IOException { - - } -} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ftp/FtpThreadTask.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ftp/FtpThreadTask.java deleted file mode 100644 index 600cefab..00000000 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ftp/FtpThreadTask.java +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.arialyy.aria.core.download.downloader.ftp; - -import android.os.Build; -import android.text.TextUtils; -import android.util.Log; -import com.arialyy.aria.core.AriaManager; -import com.arialyy.aria.core.download.DownloadEntity; -import com.arialyy.aria.core.download.DownloadTaskEntity; -import com.arialyy.aria.core.download.downloader.ChildThreadConfigEntity; -import com.arialyy.aria.core.download.downloader.IDownloadListener; -import com.arialyy.aria.core.download.downloader.StateConstance; -import com.arialyy.aria.util.BufferedRandomAccessFile; -import com.arialyy.aria.util.CommonUtil; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.math.BigDecimal; -import java.util.Properties; -import org.apache.commons.net.ftp.FTP; -import org.apache.commons.net.ftp.FTPClient; -import org.apache.commons.net.ftp.FTPFile; -import org.apache.commons.net.ftp.FTPReply; - -/** - * Created by Aria.Lao on 2017/7/24. - * Ftp下载任务 - */ -class FtpThreadTask implements Runnable { - private final String TAG = "FtpThreadTask"; - private ChildThreadConfigEntity mConfig; - private String mConfigFPath; - private long mChildCurrentLocation = 0; - private int mBufSize; - private IDownloadListener mListener; - private StateConstance STATE; - private long mSleepTime = 0; - private DownloadTaskEntity mTaskEntity; - private DownloadEntity mEntity; - - FtpThreadTask(StateConstance constance, IDownloadListener listener, - ChildThreadConfigEntity downloadInfo) { - AriaManager manager = AriaManager.getInstance(AriaManager.APP); - STATE = constance; - STATE.CONNECT_TIME_OUT = manager.getDownloadConfig().getConnectTimeOut(); - STATE.READ_TIME_OUT = manager.getDownloadConfig().getIOTimeOut(); - mListener = listener; - this.mConfig = downloadInfo; - mConfigFPath = downloadInfo.CONFIG_FILE_PATH; - mTaskEntity = mConfig.DOWNLOAD_TASK_ENTITY; - mEntity = mTaskEntity.getEntity(); - mBufSize = manager.getDownloadConfig().getBuffSize(); - setMaxSpeed(AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMsxSpeed()); - } - - void setMaxSpeed(double maxSpeed) { - if (-0.9999 < maxSpeed && maxSpeed < 0.00001) { - mSleepTime = 0; - } else { - BigDecimal db = new BigDecimal( - ((mBufSize / 1024) * (filterVersion() ? 1 : STATE.THREAD_NUM) / maxSpeed) * 1000); - mSleepTime = db.setScale(0, BigDecimal.ROUND_HALF_UP).longValue(); - } - } - - private boolean filterVersion() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; - } - - @Override public void run() { - FTPClient client = null; - InputStream is = null; - BufferedRandomAccessFile file = null; - try { - Log.d(TAG, "任务【" - + mConfig.TEMP_FILE.getName() - + "】线程__" - + mConfig.THREAD_ID - + "__开始下载【开始位置 : " - + mConfig.START_LOCATION - + ",结束位置:" - + mConfig.END_LOCATION - + "】"); - client = new FTPClient(); - //ip和端口 - String[] temp = mEntity.getDownloadUrl().split("/"); - String[] pp = temp[2].split(":"); - String dir = temp[temp.length - 2]; - String fileName = temp[temp.length - 1]; - client.connect(pp[0], Integer.parseInt(pp[1])); - if (!TextUtils.isEmpty(mTaskEntity.account)) { - client.login(mTaskEntity.userName, mTaskEntity.userPw); - } else { - client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account); - } - int reply = client.getReplyCode(); - if (!FTPReply.isPositiveCompletion(reply)) { - client.disconnect(); - failDownload(STATE.CURRENT_LOCATION, "无法连接到ftp服务器,错误码为:" + reply, null); - return; - } - client.enterLocalPassiveMode(); - client.setFileType(FTP.BINARY_FILE_TYPE); - FTPFile[] files = client.listFiles(fileName); - files[0].getSize(); - client.setRestartOffset(mConfig.START_LOCATION); - is = client.retrieveFileStream(fileName); - //创建可设置位置的文件 - file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize); - //设置每条线程写入文件的位置 - file.seek(mConfig.START_LOCATION); - byte[] buffer = new byte[mBufSize]; - int len; - //当前子线程的下载位置 - mChildCurrentLocation = mConfig.START_LOCATION; - while ((len = is.read(buffer)) != -1) { - if (STATE.isCancel) break; - if (STATE.isStop) break; - if (mSleepTime > 0) Thread.sleep(mSleepTime); - file.write(buffer, 0, len); - progress(len); - } - if (STATE.isCancel) return; - //停止状态不需要删除记录文件 - if (STATE.isStop) return; - //支持断点的处理 - if (mConfig.IS_SUPPORT_BREAK_POINT) { - Log.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】线程__" + mConfig.THREAD_ID + "__下载完毕"); - writeConfig(true, 1); - STATE.COMPLETE_THREAD_NUM++; - if (STATE.isComplete()) { - File configFile = new File(mConfigFPath); - if (configFile.exists()) { - configFile.delete(); - } - STATE.isDownloading = false; - mListener.onComplete(); - } - } else { - Log.i(TAG, "下载任务完成"); - STATE.isDownloading = false; - mListener.onComplete(); - } - } catch (IOException e) { - failDownload(mChildCurrentLocation, "下载失败【" + mConfig.DOWNLOAD_URL + "】", e); - } catch (Exception e) { - failDownload(mChildCurrentLocation, "获取流失败", e); - } finally { - try { - if (file != null) { - file.close(); - } - if (is != null) { - is.close(); - } - if (client != null) { - client.logout(); - client.disconnect(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - /** - * 停止下载 - */ - protected void stop() { - synchronized (AriaManager.LOCK) { - try { - STATE.STOP_NUM++; - Log.d(TAG, "任务【" - + mConfig.TEMP_FILE.getName() - + "】thread__" - + mConfig.THREAD_ID - + "__停止, stop location ==> " - + mChildCurrentLocation); - writeConfig(false, mChildCurrentLocation); - if (STATE.isStop()) { - Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已停止"); - STATE.isDownloading = false; - mListener.onStop(STATE.CURRENT_LOCATION); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - /** - * 下载中 - */ - private void progress(long len) { - synchronized (AriaManager.LOCK) { - mChildCurrentLocation += len; - STATE.CURRENT_LOCATION += len; - } - } - - /** - * 取消下载 - */ - protected void cancel() { - synchronized (AriaManager.LOCK) { - STATE.CANCEL_NUM++; - Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__取消下载"); - if (STATE.isCancel()) { - File configFile = new File(mConfigFPath); - if (configFile.exists()) { - configFile.delete(); - } - if (mConfig.TEMP_FILE.exists()) { - mConfig.TEMP_FILE.delete(); - } - Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已取消"); - STATE.isDownloading = false; - mListener.onCancel(); - } - } - } - - /** - * 下载失败 - */ - private void failDownload(long currentLocation, String msg, Exception ex) { - synchronized (AriaManager.LOCK) { - try { - STATE.FAIL_NUM++; - STATE.isDownloading = false; - STATE.isStop = true; - if (ex != null) { - Log.e(TAG, msg + "\n" + CommonUtil.getPrintException(ex)); - } - writeConfig(false, currentLocation); - if (STATE.isFail()) { - Log.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】下载失败"); - mListener.onFail(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - /** - * 将记录写入到配置文件 - */ - private void writeConfig(boolean isComplete, long record) throws IOException { - synchronized (AriaManager.LOCK) { - String key = null, value = null; - if (0 < record && record < mConfig.END_LOCATION) { - key = mConfig.TEMP_FILE.getName() + "_record_" + mConfig.THREAD_ID; - value = String.valueOf(record); - } else if (record >= mConfig.END_LOCATION || isComplete) { - key = mConfig.TEMP_FILE.getName() + "_state_" + mConfig.THREAD_ID; - value = "1"; - } - if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) { - File configFile = new File(mConfigFPath); - Properties pro = CommonUtil.loadConfig(configFile); - pro.setProperty(key, value); - CommonUtil.saveConfig(configFile, pro); - } - } - } -} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/http/HttpThreadTask.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/http/HttpThreadTask.java deleted file mode 100644 index 07f006d1..00000000 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/http/HttpThreadTask.java +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.arialyy.aria.core.download.downloader.http; - -import android.os.Build; -import android.text.TextUtils; -import android.util.Log; -import com.arialyy.aria.core.AriaManager; -import com.arialyy.aria.core.download.downloader.ChildThreadConfigEntity; -import com.arialyy.aria.core.download.downloader.IDownloadListener; -import com.arialyy.aria.core.download.downloader.StateConstance; -import com.arialyy.aria.util.BufferedRandomAccessFile; -import com.arialyy.aria.util.CommonUtil; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.math.BigDecimal; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Properties; - -/** - * Created by lyy on 2017/1/18. - * 下载线程 - */ -final class HttpThreadTask implements Runnable { - private static final String TAG = "HttpThreadTask"; - private ChildThreadConfigEntity mConfigEntity; - private String mConfigFPath; - private long mChildCurrentLocation = 0; - private int mBufSize; - private IDownloadListener mListener; - private StateConstance STATE; - private long mSleepTime = 0; - - HttpThreadTask(StateConstance constance, IDownloadListener listener, - ChildThreadConfigEntity downloadInfo) { - AriaManager manager = AriaManager.getInstance(AriaManager.APP); - STATE = constance; - STATE.CONNECT_TIME_OUT = manager.getDownloadConfig().getConnectTimeOut(); - STATE.READ_TIME_OUT = manager.getDownloadConfig().getIOTimeOut(); - mListener = listener; - this.mConfigEntity = downloadInfo; - if (mConfigEntity.IS_SUPPORT_BREAK_POINT) { - mConfigFPath = downloadInfo.CONFIG_FILE_PATH; - } - mBufSize = manager.getDownloadConfig().getBuffSize(); - setMaxSpeed(AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMsxSpeed()); - } - - void setMaxSpeed(double maxSpeed) { - if (-0.9999 < maxSpeed && maxSpeed < 0.00001) { - mSleepTime = 0; - } else { - BigDecimal db = new BigDecimal( - ((mBufSize / 1024) * (filterVersion() ? 1 : STATE.THREAD_NUM) / maxSpeed) * 1000); - mSleepTime = db.setScale(0, BigDecimal.ROUND_HALF_UP).longValue(); - } - } - - private boolean filterVersion() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; - } - - @Override public void run() { - HttpURLConnection conn = null; - InputStream is = null; - BufferedRandomAccessFile file = null; - try { - URL url = new URL(mConfigEntity.DOWNLOAD_URL); - conn = ConnectionHelp.handleConnection(url); - if (mConfigEntity.IS_SUPPORT_BREAK_POINT) { - Log.d(TAG, "任务【" - + mConfigEntity.TEMP_FILE.getName() - + "】线程__" - + mConfigEntity.THREAD_ID - + "__开始下载【开始位置 : " - + mConfigEntity.START_LOCATION - + ",结束位置:" - + mConfigEntity.END_LOCATION - + "】"); - //在头里面请求下载开始位置和结束位置 - conn.setRequestProperty("Range", - "bytes=" + mConfigEntity.START_LOCATION + "-" + (mConfigEntity.END_LOCATION - 1)); - } else { - Log.w(TAG, "该下载不支持断点"); - } - conn = ConnectionHelp.setConnectParam(mConfigEntity.DOWNLOAD_TASK_ENTITY, conn); - conn.setConnectTimeout(STATE.CONNECT_TIME_OUT); - conn.setReadTimeout(STATE.READ_TIME_OUT); //设置读取流的等待时间,必须设置该参数 - is = conn.getInputStream(); - //创建可设置位置的文件 - file = new BufferedRandomAccessFile(mConfigEntity.TEMP_FILE, "rwd", mBufSize); - //设置每条线程写入文件的位置 - file.seek(mConfigEntity.START_LOCATION); - byte[] buffer = new byte[mBufSize]; - int len; - //当前子线程的下载位置 - mChildCurrentLocation = mConfigEntity.START_LOCATION; - while ((len = is.read(buffer)) != -1) { - if (STATE.isCancel) break; - if (STATE.isStop) break; - if (mSleepTime > 0) Thread.sleep(mSleepTime); - file.write(buffer, 0, len); - progress(len); - } - if (STATE.isCancel) return; - //停止状态不需要删除记录文件 - if (STATE.isStop) return; - //支持断点的处理 - if (mConfigEntity.IS_SUPPORT_BREAK_POINT) { - Log.i(TAG, "任务【" - + mConfigEntity.TEMP_FILE.getName() - + "】线程__" - + mConfigEntity.THREAD_ID - + "__下载完毕"); - writeConfig(true, 1); - STATE.COMPLETE_THREAD_NUM++; - if (STATE.isComplete()) { - File configFile = new File(mConfigFPath); - if (configFile.exists()) { - configFile.delete(); - } - STATE.isDownloading = false; - mListener.onComplete(); - } - } else { - Log.i(TAG, "下载任务完成"); - STATE.isDownloading = false; - mListener.onComplete(); - } - } catch (MalformedURLException e) { - failDownload(mChildCurrentLocation, "下载链接异常", e); - } catch (IOException e) { - failDownload(mChildCurrentLocation, "下载失败【" + mConfigEntity.DOWNLOAD_URL + "】", e); - } catch (Exception e) { - failDownload(mChildCurrentLocation, "获取流失败", e); - } finally { - try { - if (file != null) { - file.close(); - } - if (is != null) { - is.close(); - } - if (conn != null) { - conn.disconnect(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - /** - * 停止下载 - */ - protected void stop() { - synchronized (AriaManager.LOCK) { - try { - if (mConfigEntity.IS_SUPPORT_BREAK_POINT) { - STATE.STOP_NUM++; - Log.d(TAG, "任务【" - + mConfigEntity.TEMP_FILE.getName() - + "】thread__" - + mConfigEntity.THREAD_ID - + "__停止, stop location ==> " - + mChildCurrentLocation); - writeConfig(false, mChildCurrentLocation); - if (STATE.isStop()) { - Log.d(TAG, "任务【" + mConfigEntity.TEMP_FILE.getName() + "】已停止"); - STATE.isDownloading = false; - mListener.onStop(STATE.CURRENT_LOCATION); - } - } else { - Log.d(TAG, "任务【" + mConfigEntity.TEMP_FILE.getName() + "】已停止"); - STATE.isDownloading = false; - mListener.onStop(STATE.CURRENT_LOCATION); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - /** - * 下载中 - */ - private void progress(long len) { - synchronized (AriaManager.LOCK) { - mChildCurrentLocation += len; - STATE.CURRENT_LOCATION += len; - } - } - - /** - * 取消下载 - */ - protected void cancel() { - synchronized (AriaManager.LOCK) { - if (mConfigEntity.IS_SUPPORT_BREAK_POINT) { - STATE.CANCEL_NUM++; - Log.d(TAG, "任务【" - + mConfigEntity.TEMP_FILE.getName() - + "】thread__" - + mConfigEntity.THREAD_ID - + "__取消下载"); - if (STATE.isCancel()) { - File configFile = new File(mConfigFPath); - if (configFile.exists()) { - configFile.delete(); - } - if (mConfigEntity.TEMP_FILE.exists()) { - mConfigEntity.TEMP_FILE.delete(); - } - Log.d(TAG, "任务【" + mConfigEntity.TEMP_FILE.getName() + "】已取消"); - STATE.isDownloading = false; - mListener.onCancel(); - } - } else { - Log.d(TAG, "任务【" + mConfigEntity.TEMP_FILE.getName() + "】已取消"); - STATE.isDownloading = false; - mListener.onCancel(); - } - } - } - - /** - * 下载失败 - */ - private void failDownload(long currentLocation, String msg, Exception ex) { - synchronized (AriaManager.LOCK) { - try { - STATE.FAIL_NUM++; - STATE.isDownloading = false; - STATE.isStop = true; - if (ex != null) { - Log.e(TAG, msg + "\n" + CommonUtil.getPrintException(ex)); - } - if (mConfigEntity.IS_SUPPORT_BREAK_POINT) { - writeConfig(false, currentLocation); - if (STATE.isFail()) { - Log.e(TAG, "任务【" + mConfigEntity.TEMP_FILE.getName() + "】下载失败"); - mListener.onFail(); - } - } else { - Log.e(TAG, "任务【" + mConfigEntity.TEMP_FILE.getName() + "】下载失败"); - mListener.onFail(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - /** - * 将记录写入到配置文件 - */ - private void writeConfig(boolean isComplete, long record) throws IOException { - synchronized (AriaManager.LOCK) { - String key = null, value = null; - if (0 < record && record < mConfigEntity.END_LOCATION) { - key = mConfigEntity.TEMP_FILE.getName() + "_record_" + mConfigEntity.THREAD_ID; - value = String.valueOf(record); - } else if (record >= mConfigEntity.END_LOCATION || isComplete) { - key = mConfigEntity.TEMP_FILE.getName() + "_state_" + mConfigEntity.THREAD_ID; - value = "1"; - } - if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) { - File configFile = new File(mConfigFPath); - Properties pro = CommonUtil.loadConfig(configFile); - pro.setProperty(key, value); - CommonUtil.saveConfig(configFile, pro); - } - } - } -} diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTaskEntity.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTaskEntity.java index 8217f7ce..d28de70d 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTaskEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTaskEntity.java @@ -39,6 +39,11 @@ public abstract class AbsTaskEntity extends DbEntity { */ public Map headers = new HashMap<>(); + /** + * 字符编码,默认为"utf-8" + */ + public String charSet = "utf-8"; + /** * 网络请求类型 */ diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadUtil.java index c0ee07d7..fcad3cb0 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadUtil.java @@ -102,7 +102,7 @@ final class UploadUtil implements Runnable { mListener.onPostPre(uploadFile.length()); PrintWriter writer = - new PrintWriter(new OutputStreamWriter(mOutputStream, mTaskEntity.charset), true); + new PrintWriter(new OutputStreamWriter(mOutputStream, mTaskEntity.charSet), true); //添加文件上传表单字段 keys = mTaskEntity.formFields.keySet(); @@ -143,7 +143,7 @@ final class UploadUtil implements Runnable { .append("\"") .append(LINE_END); writer.append("Content-Type: text/plain; charset=") - .append(mTaskEntity.charset) + .append(mTaskEntity.charSet) .append(LINE_END); writer.append(LINE_END); writer.append(value).append(LINE_END); diff --git a/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java b/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java index 769eb2ab..2a941bae 100644 --- a/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java @@ -37,6 +37,7 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.UnsupportedEncodingException; import java.lang.reflect.Field; import java.math.BigDecimal; import java.math.BigInteger; @@ -63,6 +64,18 @@ import java.lang.reflect.WildcardType; public class CommonUtil { private static final String TAG = "CommonUtil"; + /** + * 字符串编码转换 + */ + public static String strCharSetConvert(String oldStr, String charSet) { + try { + return new String(oldStr.getBytes(), charSet); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return null; + } + /** * 实例化泛型的实际类型参数 * diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4443482d..8eb58811 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -32,6 +32,7 @@ + diff --git a/app/src/main/assets/aria_config.xml b/app/src/main/assets/aria_config.xml index 43a593a2..7e615062 100644 --- a/app/src/main/assets/aria_config.xml +++ b/app/src/main/assets/aria_config.xml @@ -5,7 +5,7 @@ - + diff --git a/app/src/main/java/com/arialyy/simple/MainActivity.java b/app/src/main/java/com/arialyy/simple/MainActivity.java index 5867a402..e05201b1 100644 --- a/app/src/main/java/com/arialyy/simple/MainActivity.java +++ b/app/src/main/java/com/arialyy/simple/MainActivity.java @@ -23,6 +23,7 @@ import butterknife.OnClick; import com.arialyy.simple.base.BaseActivity; import com.arialyy.simple.databinding.ActivityMainBinding; import com.arialyy.simple.download.DownloadActivity; +import com.arialyy.simple.download.FtpDownloadActivity; import com.arialyy.simple.download.group.DownloadGroupActivity; import com.arialyy.simple.test.TestMutilTaskSysDownload; import com.arialyy.simple.upload.UploadActivity; @@ -44,7 +45,7 @@ public class MainActivity extends BaseActivity { } - @OnClick({R.id.download, R.id.upload, R.id.download_task_group}) + @OnClick({R.id.download, R.id.upload, R.id.download_task_group, R.id.ftp}) public void funcation(View view){ switch (view.getId()){ case R.id.download: @@ -56,6 +57,9 @@ public class MainActivity extends BaseActivity { case R.id.download_task_group: startActivity(new Intent(this, DownloadGroupActivity.class)); break; + case R.id.ftp: + startActivity(new Intent(this, FtpDownloadActivity.class)); + break; } } diff --git a/app/src/main/java/com/arialyy/simple/download/FtpDownloadActivity.java b/app/src/main/java/com/arialyy/simple/download/FtpDownloadActivity.java new file mode 100644 index 00000000..36f123ac --- /dev/null +++ b/app/src/main/java/com/arialyy/simple/download/FtpDownloadActivity.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.arialyy.simple.download; + +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import com.arialyy.annotations.Download; +import com.arialyy.aria.core.Aria; +import com.arialyy.aria.core.download.DownloadTask; +import com.arialyy.aria.util.CommonUtil; +import com.arialyy.frame.util.show.L; +import com.arialyy.frame.util.show.T; +import com.arialyy.simple.R; +import com.arialyy.simple.base.BaseActivity; +import com.arialyy.simple.databinding.ActivityFtpDownloadBinding; +import java.io.File; + +/** + * Created by Aria.Lao on 2017/7/25. + * Ftp下载测试 + */ +public class FtpDownloadActivity extends BaseActivity { + + @Override protected void init(Bundle savedInstanceState) { + super.init(savedInstanceState); + Aria.download(this).register(); + } + + public void onClick(View view) { + switch (view.getId()) { + case R.id.start: + Aria.download(this) + //.load("172.18.104.129", "21", "cd.mp3") + .load("172.18.104.129", "21", "gg.png") + .login("lao", "123456") + .setDownloadPath("/mnt/sdcard/tt.png") + .charSet("gbk") + .start(); + break; + case R.id.stop: + break; + case R.id.cancel: + break; + } + } + + @Download.onPre() protected void onPre(DownloadTask task) { + L.d(TAG, "ftp pre"); + } + + @Download.onTaskPre() protected void onTaskPre(DownloadTask task) { + L.d(TAG, "ftp task pre"); + getBinding().setFileSize(task.getConvertFileSize()); + } + + @Download.onTaskStart() void taskStart(DownloadTask task) { + L.d(TAG, "ftp task start"); + } + + @Download.onTaskRunning() protected void running(DownloadTask task) { + getBinding().setProgress(task.getPercent()); + getBinding().setSpeed(task.getConvertSpeed()); + } + + @Download.onTaskResume() void taskResume(DownloadTask task) { + L.d(TAG, "ftp task resume"); + } + + @Download.onTaskStop() void taskStop(DownloadTask task) { + L.d(TAG, "ftp task stop"); + getBinding().setSpeed(""); + } + + @Download.onTaskCancel() void taskCancel(DownloadTask task) { + getBinding().setSpeed(""); + getBinding().setProgress(0); + } + + @Download.onTaskFail() void taskFail(DownloadTask task) { + L.d(TAG, "ftp task fail"); + } + + @Download.onTaskComplete() void taskComplete(DownloadTask task) { + getBinding().setProgress(100); + Log.d(TAG, "md5 ==> " + CommonUtil.getFileMD5(new File(task.getDownloadPath()))); + T.showShort(this, "FTP下载完成"); + } + + @Override protected int setLayoutId() { + return R.layout.activity_ftp_download; + } +} diff --git a/app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java b/app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java index b5471182..cfa5edba 100644 --- a/app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java +++ b/app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java @@ -38,9 +38,6 @@ import java.util.List; */ public class DownloadGroupActivity extends BaseActivity { - @Bind(R.id.start) Button mStart; - @Bind(R.id.stop) Button mStop; - @Bind(R.id.cancel) Button mCancel; @Bind(R.id.child_list) SubStateLinearLayout mChildList; List mUrls; diff --git a/app/src/main/res/layout/activity_ftp_download.xml b/app/src/main/res/layout/activity_ftp_download.xml new file mode 100644 index 00000000..46ac3b31 --- /dev/null +++ b/app/src/main/res/layout/activity_ftp_download.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 17407578..7b175e0c 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -33,5 +33,13 @@ style="?buttonBarButtonStyle" /> +