从网上下载文件(源码)

import java.io.BufferedInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;

import android.util.Log;


/**
 * 下载
 * 
 */
public class DownLoadTask implements Runnable {
public static final int ERROR = 0;// 未知错误
public static final int ERROR_FILENOTFOUND = 1;// 保存文件地址没有找到
public static final int ERROR_CONNECTEXCEPTION = 2;// 连接超时异常
public static final int ERROR_THREAD = 4;// 子线程异常
private static final String TAG = "DownLoadTask";

private String url = ""; // url地址
private int threadCount = 4;// 线程数量
private String savePath; // 保存地址
public static int connectTimeout = 10000;// 毫秒
private List<DownLoadThread> threads; // 持有下载线程的引用集合
private ArrayBlockingQueue<DownMessage> queue;// 消息队列
private ArrayBlockingQueue<DownMessage> buffer;// 消息缓存队列
private DownInfo info;
private DownlaodListener listener;
/** 是否继续下载 */
private boolean flag;

private DownLoadTask() {
queue = new ArrayBlockingQueue<DownMessage>(100);
buffer = new ArrayBlockingQueue<DownMessage>(100);
}

/**
 * 下载一个存在线程的DwonInfo
 */
public DownLoadTask(DownInfo info) {
this();
this.url = info.url;
this.savePath = info.savePath;
this.threadCount = info.threads.size();
this.info = info;
}

public void setListener(DownlaodListener listener) {
this.listener = listener;
}

/**
 * 下载一个新的路径
 * 
 * @param url
 * @param savePath
 * @param threadId
 */
public DownLoadTask(String url, String savePath, int threadId) {
this();
this.url = url;
this.savePath = savePath;
this.threadCount = threadId;
}

@Override
public void run() {
HttpURLConnection conn = null;
int countSucess = 0;// 已完成总线程数
try {
long starttime = System.currentTimeMillis();
Log.d(TAG, "开始下载URL = " + url);
URL urlconn = new URL(url);
conn = (HttpURLConnection) urlconn.openConnection();
conn.setConnectTimeout(connectTimeout);
int length = conn.getContentLength();
int responseCode = conn.getResponseCode();
if (HttpURLConnection.HTTP_OK != responseCode || length < 0) {
notifyListenerError(ERROR);
return;
}

if (info != null) {
if (info.length != length)
Log.d(TAG, "地址数据已更改,重新下载");
}
RandomAccessFile randFile = new RandomAccessFile(savePath, "rwd");
randFile.setLength(length);

start(length);// 开始下载

int stop = 0;
DownMessage msg;
flag = true;
while (threadCount != countSucess && flag && threadCount != stop) {
msg = queue.take();
switch (msg.type) {
case DownMessage.MSG_SUCCESS:
countSucess++;
Log.d(TAG, "线程Id=" + msg.threadid + "已完成下载");
break;
case DownMessage.MSG_UPDATE:
if (listener != null) {
listener.update(length, msg.data, msg.threadid);
}
break;
case DownMessage.MSG_ERROR:
flag = false;
for (DownLoadThread thread : threads) {
thread.canleDown();
}
break;
case DownMessage.MSG_STOP:
stop++;
break;
}
recyle(msg);
}

Log.d(TAG, "耗时" + (System.currentTimeMillis() - starttime));

} catch (Throwable e) {
if (e instanceof ConnectException) {
notifyListenerError(ERROR_CONNECTEXCEPTION);
Log.e(TAG, "连接异常", e);
} else if (e instanceof FileNotFoundException) {
notifyListenerError(ERROR_FILENOTFOUND);
Log.e(TAG, "文件路径错误", e);
} else if (e instanceof SocketTimeoutException) {
notifyListenerError(ERROR_FILENOTFOUND);
Log.e(TAG, "连接超时", e);
} else {
Log.e(TAG, e+"");
}

} finally {
if (conn != null)
conn.disconnect();
conn = null;
if (listener != null)
listener.downLoadFinish(countSucess);
Release();
}
}

/** 取消下载 */
public void cancel() {
flag = false;
Release();
}

private void start(int length) throws FileNotFoundException {
if (length < threadCount)
threadCount = 1;
threads = new ArrayList<DownLoadThread>();
DownLoadThread downLoadThread;
int start = 0;
if (threadCount > 1) {
int size = length / threadCount;
int end;
for (int i = 0; i < threadCount; i++) {
if (i == threadCount - 1) {
start = i * size;
end = length - 1;
} else {
start = i * size;
end = (i + 1) * size - 1;
}
if (info != null) {
start += info.threads.get(i);
}
downLoadThread = new DownLoadThread(start, end, new RandomAccessFile(savePath, "rwd"), url, i, queue,
buffer);
threads.add(downLoadThread);
downLoadThread.start();
}
} else {
if (info != null) {
start += info.threads.get(0);
}
downLoadThread = new DownLoadThread(start, length - 1, new RandomAccessFile(savePath, "rwd"), url, 0,
queue, buffer);
threads.add(downLoadThread);
downLoadThread.start();
}
}

/**
 * 如果监听器不为空通知发送错误
 * 
 * @param type
 */
private void notifyListenerError(int type) {
if (listener != null)
listener.downLoadError(type);
}

/**
 * 回收 DownMessage 对象
 * 
 * @param msg
 */
private void recyle(DownMessage msg) {
if (flag) {
msg.type = -1;
msg.threadid = -1;
buffer.offer(msg);
}
}

private void Release() {
if (threads != null) {
for (DownLoadThread thread : threads) {
thread.canleDown();
}
}
queue = null;
buffer = null;
info = null;
listener = null;
}

/**
 * 下载线程
 * 
 */
public static class DownLoadThread extends Thread {

private int start;// 开始位置
private int end;// 结束位置
private RandomAccessFile file;// 存放的文件
private String url;
private int threadid;
private boolean flag = true;
private ArrayBlockingQueue<DownMessage> queue;// 消息队列
private ArrayBlockingQueue<DownMessage> bufferMsg;// 缓存队列
private DownMessage msg;// 消息

public DownLoadThread(int start, int end, RandomAccessFile file, String url, int threadid,
ArrayBlockingQueue<DownMessage> queue, ArrayBlockingQueue<DownMessage> bufferMsg) {
this.start = start;
this.end = end;
this.file = file;
this.url = url;
this.threadid = threadid;
this.queue = queue;
this.bufferMsg = bufferMsg;
}

/**
 * 当出现错误调用方法,取消线程下载,让线程正常结束
 */
public void canleDown() {
flag = false;
}

@Override
public void run() {
InputStream is = null;
HttpURLConnection conn = null;
try {
file.seek(start);
URL connUrl = new URL(url);
conn = (HttpURLConnection) connUrl.openConnection();
conn.setRequestMethod("POST");
conn.setConnectTimeout(DownLoadTask.connectTimeout);
conn.setRequestProperty("Range", "bytes=" + start + "-" + end);
int responseCode = conn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_PARTIAL || responseCode == HttpURLConnection.HTTP_OK) {
is = new BufferedInputStream(conn.getInputStream(), 8192);
byte[] buffer = new byte[8192];// 10K缓存
int len = 0;
while ((len = is.read(buffer)) != -1 && flag) {
file.write(buffer, 0, len);
sendMessage(DownMessage.MSG_UPDATE, len);
}
sendMessage(DownMessage.MSG_SUCCESS, 0);
} else {
sendMessage(DownMessage.MSG_ERROR, 10);
}
} catch (Exception e) {
e.printStackTrace();
try {
sendMessage(DownMessage.MSG_ERROR, 0);
} catch (InterruptedException e1) {
e1.printStackTrace();
}

} finally {
try {
sendMessage(DownMessage.MSG_STOP, 0);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
if (file != null) {
try {
file.close();
} catch (IOException e) {
}
}
file = null;
if (is != null) {
try {
is.close();
} catch (IOException e) {
}
}
is = null;
if (conn != null)
conn.disconnect();
conn = null;

Release();
}
}

private void sendMessage(int type, int data) throws InterruptedException {
msg = bufferMsg.poll();
if (msg == null)
msg = new DownMessage(type, data, threadid);
else {
msg.type = type;
msg.data = data;
msg.threadid = threadid;
}
queue.put(msg);
}

private void Release() {
file = null;
queue = null;
bufferMsg = null;
}
}

/**
 * 下载消息
 * 
 */
public static class DownMessage {
public static final int MSG_SUCCESS = 0;
public static final int MSG_UPDATE = 1;
public static final int MSG_ERROR = 2;
public static final int MSG_STOP = 3;
int type;
int data;
int threadid;

public DownMessage(int type, int data, int threadid) {
this.type = type;
this.data = data;
this.threadid = threadid;
}
}

public static class DownInfo {
private String url = ""; // url地址
private String savePath; // 保存地址
private int length;//总长度
/** <线程, 已下载数量>
 *  注意需要下载的所有线程
 * */
private Map<Integer, Integer> threads;

public DownInfo(String url, String savePath, Map<Integer, Integer> threads) {
this.url = url;
this.savePath = savePath;
this.threads = threads;
}

public int getLength() {
return length;
}

public void setLength(int length) {
this.length = length;
}

public String getUrl() {
return url;
}

public void setUrl(String url) {
this.url = url;
}

public String getSavePath() {
return savePath;
}

public void setSavePath(String savePath) {
this.savePath = savePath;
}

public Map<Integer, Integer> getThreads() {
return threads;
}

public void setThreads(Map<Integer, Integer> threads) {
this.threads = threads;
}
}

public static interface DownlaodListener {
void update(int total, int len, int threadid);

void downLoadFinish(int totalSucess);

void downLoadError(int type);
}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: curl 是一个强大的开源库,用于在命令行进行文件传输。它支持多种协议,如HTTP、FTP、SMTP等,并且能够使用各种功能,如文件上传、下载、断点续传等。 要使用curl库下载文件,首先需要在计算机上安装curl。然后,可以使用curl命令来进行文件下载。使用curl库下载文件的命令格式为: curl -o <要保存的文件名> <文件的URL> 其,-o参数用于指定要保存的文件名,<文件的URL>是要下载文件的网址。 例如,要下载一个名为example.txt的文件,可以使用以下命令: curl -o example.txt https://www.example.com/example.txt 执行该命令后,curl会将文件从URL下载到当前目录,并保存为example.txt。 使用curl库还可以进行一些其他操作。例如,可以使用-c参数来设置下载的断点,以便在下载断后能够从上次断的位置恢复下载。还可以使用-u参数来指定下载需要的用户名和密码,以便访问需要身份验证的网页。 总之,使用curl库可以方便地下载文件源码。只需提供文件的URL和保存的文件名,即可快速下载文件。同时,curl还提供了其他高级功能,可以满足更多的下载需求。无论是从HTTP、FTP还是SMTP等协议,curl都能提供稳定和强大的文件下载能力。 ### 回答2: Curl库是一个开源的网络数据传输工具,支持多种网络协议,可以用于下载文件源码。使用Curl库下载文件源码的步骤如下: 1. 首先,需要在代码引入Curl库的头文件。可以通过以下代码实现: ```c #include <curl/curl.h> ``` 2. 创建一个Curl句柄,用于管理下载操作,并对其进行初始化。可以使用以下代码完成初始化: ```c CURL *curl; curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); ``` 3. 设置下载的URL地址。可以使用以下代码设置URL: ```c curl_easy_setopt(curl, CURLOPT_URL, "http://example.com/source_code.tar.gz"); ``` 4. 设置下载文件的保存路径。可以使用以下代码设置保存路径: ```c FILE *file; file = fopen("source_code.tar.gz", "wb"); curl_easy_setopt(curl, CURLOPT_WRITEDATA, file); ``` 5. 执行下载并保存文件。使用以下代码执行下载操作: ```c CURLcode res; res = curl_easy_perform(curl); ``` 6. 下载完成后,记得关闭文件和释放Curl句柄。使用以下代码完成操作: ```c fclose(file); curl_easy_cleanup(curl); curl_global_cleanup(); ``` 通过以上步骤,就可以使用Curl库下载文件源码了。可以根据实际需求进行适当的修改,例如设置代理、设置下载进度等。 ### 回答3: 使用curl库下载文件源码可以分为以下几个步骤: 1. 引入curl库 首先需要在代码引入curl库,如下所示: #include <curl/curl.h> 2. 初始化curl库 在使用curl库之前,需要对其进行初始化,可以调用curl_global_init函数,如下所示: curl_global_init(CURL_GLOBAL_DEFAULT); 3. 创建CURL句柄 创建一个CURL句柄,用于访问和处理URL请求,如下所示: CURL *curl = curl_easy_init(); 4. 设置URL地址 设置要下载文件的URL地址,通过调用curl_easy_setopt函数设置,如下所示: curl_easy_setopt(curl, CURLOPT_URL, "https://www.example.com/file.txt"); 5. 设置写入数据函数 设置写入数据的回调函数,当curl接收到数据时,会调用该函数进行数据的写入,如下所示: size_t WriteData(void *buffer, size_t size, size_t nmemb, void *stream) { // 在此处将数据写入文件 ... return nmemb; } curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteData); 6. 发起请求并下载文件 通过调用curl_easy_perform函数来发起请求并下载文件,如下所示: CURLcode res = curl_easy_perform(curl); if(res != CURLE_OK) { // 下载失败的处理逻辑 ... } 7. 清理及释放资源 下载完成后,需要进行清理及资源的释放,如下所示: curl_easy_cleanup(curl); curl_global_cleanup(); 通过以上步骤,可以使用curl库下载文件源码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值