千家信息网

Android中如何利用FTP实现多线程断点续传下载上传功能

发表于:2025-11-08 作者:千家信息网编辑
千家信息网最后更新 2025年11月08日,这篇文章主要介绍了Android中如何利用FTP实现多线程断点续传下载上传功能的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Android中如何利用FTP实现多线程断点续
千家信息网最后更新 2025年11月08日Android中如何利用FTP实现多线程断点续传下载上传功能

这篇文章主要介绍了Android中如何利用FTP实现多线程断点续传下载上传功能的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Android中如何利用FTP实现多线程断点续传下载上传功能文章都会有所收获,下面我们一起来看看吧。

FTP下载原理

FTP单线程断点续传

FTP和传统的HTTP协议有所不同,由于FTP没有所谓的头文件,因此我们不能像HTTP那样通过设置header向服务器指定下载区间。

但是FTP协议提供了一个更好用的命令REST用于从指定位置恢复任务,同时FTP协议也提供了一个命令SIZE用于获取下载的文件大小,有了这两个命令,FTP断点续传也就没有什么问题。

FTP断点续传的原理和HTTP的断点续传原理差不多,在暂停时记录文件的停止位置,再次下载时,先读取记录的位置,如果位置存在,则通过REST命令告诉服务器从指定区间进行下载。

FTP多线程断点续传

多线程下载的原理和HTTP多线程下载的原理差不多。先获取文件大小,然后根据线程数,对整个文件进行分段下载,在任务停止时,记录每一条线程的暂停位置,重新开始下载,每一条线程读取对应的下载记录,然后每一线程从指定位置开始下载。

分段下载

和HTTP所不同的是,FTP并没有提供文件区间的API,因此,FTP在分段下载中,只有起始位置而没有结束位置。
因此,你需要在指定位置手动停止线程。

功能实现

本文使用将采用apache commons-net实现FTP断点续传下载\上传功能。

通过下文的几步操作,你就能很简单的实现FTP断点续传。

登录

FTP协议和HTTP协议有所不同,使用FTP进行下载时,你需要进行登录操作。

当然,如果你服务器没有登录功能,你可以忽略登录操作。

FTPClient client = new FTPClient();client.connect(serverIp, port); //连接到FTP服务器client.login(userName, passsword);

通过上面三行代码,就可以很简单的登录到FTP服务器上。

在进行登录后,还需要验证是否登录成功

int reply = client.getReplyCode();if (!FTPReply.isPositiveCompletion(reply)) {  client.disconnect();  Log.d(TAG, "无法连接到ftp服务器,错误码为:" + reply);  return; }

由于FTP协议中,连接成功的状态有多个,因此需要通过FTPReply.isPositiveCompletion(reply)用于验证是否成功连接到FTP服务器。

文件信息获取

在连接到FTP服务器后,就需要开始获取下载最重要的几个参数(文件长度、文件名)。

客户端可以通过client.listFiles(remotePath)获取FTP服务器上该路径的文件列表。

  • 如果路径是文件,只会返回一个长度为1的数组。

  • 如果该路径为文件夹,则会返回该文件夹下对应的所有文件。

String remotePath = "/upload/qjnn.apk"; //FTP服务器上文件路径FTPFile[] files = client.listFiles(remotePath);FTPFile file = files[0]; //文件信息long size = file.getSize();String fileaName = file.getName();

如果你的文件为英文名,并且路径中没有中文,那么通过上述代码,便可以获取到正确的文件信息。

但如果FTP上的服务器上的文件名有中文或路径有中文,那么上述代码,你将获取不到正确的文件信息。

正确的写法

由于FTP服务器默认的编码是ISO-8859-1,因此,客户端在获取文件信息时

  • 需要请求服务器使用UTF-8编码(如果服务器支持的话),如果服务器不支持开启UTF-8编码,那么客户端需要指定字符串编码格式

  • 客户端在请求remotePath路径、获取文件名时,都需要对路径进行编码转换处理。

String remotePath = "/upload/qjnn.apk"; //FTP服务器上文件路径String charSet = "UTF-8";if (!FTPReply.isPositiveCompletion(client.sendCommand("OPTS UTF8", "ON"))) {  //向服务器请求使用"UTF-8"编码  charSet = "GBK";}FTPFile[] files = client.listFiles(new String(remotePath.getBytes(charSet), "ISO-8859-1")); //对remotePath进行编码转换FTPFile file = files[0]; //文件信息long size = file.getSize();String fileaName = new String(fileName.getBytes(), Charset.forName(charSet));

通过以上代码,便可以获取到正确的文件信息。

文件下载

配置每条线程的下载区间

long fileLength = mEntity.getFileSize();Properties pro = CommonUtil.loadConfig(mConfigFile);int blockSize = (int) (fileLength / mThreadNum);int[] recordL = new int[mThreadNum];for (int i = 0; i < mThreadNum; i++) { recordL[i] = -1;}int rl = 0;for (int i = 0; i < mThreadNum; i++) { long startL = i * blockSize, endL = (i + 1) * blockSize; Object state = pro.getProperty(mTempFile.getName() + "_state_" + i); if (state != null && Integer.parseInt(state + "") == 1) { //该线程已经完成  if (resumeRecordLocation(i, startL, endL)) return;  continue; } //分配下载位置 Object record = pro.getProperty(fileName + "_record_" + i); //如果有记录,则恢复下载 if (record != null && Long.parseLong(record + "") >= 0) {  Long r = Long.parseLong(record + "");  mConstance.CURRENT_LOCATION += r - startL;  Log.d(TAG, "任务【" + mEntity.getFileName() + "】线程__" + i + "__恢复下载");  startL = r;  recordL[rl] = i;  rl++; } else {  recordL[rl] = i;  rl++; } //最后一个线程的结束位置即为文件的总长度 if (i == (mThreadNum - 1)) endL = fileLength; //创建分段线程 AbsThreadTask task = createSingThreadTask(i, startL, endL, fileLength); if (task == null) return; mTask.put(i, task);}startSingleTask(recordL);

在上面的代码中,主要做了两步操作:

  • 在文件下载前,先从本地文件中读取当前下载的每一条线程的下载情况

  • 如果下载记录存在,从记录位置开始下载,如果记录不存在,则重新开始下载

FTP 分段线程区间自动停止

由于FTP协议没有区间下载的原因,为了让线程只下载特定区间的内容,需要客户端在单条线程累计读的数据长度已经超过了所分配的区间长度的时候,停止该条线程。

 client.enterLocalPassiveMode();  //设置被动模式 client.setFileType(FTP.BINARY_FILE_TYPE); //设置文件传输模式 client.setRestartOffset(mConfig.START_LOCATION);  //设置恢复下载的位置 client.allocate(mBufSize); is = client.retrieveFileStream(new String(remotePath.getBytes(charSet), SERVER_CHARSET)); //发送第二次指令时,还需要再做一次判断 reply = client.getReplyCode(); if (!FTPReply.isPositivePreliminary(reply)) {  client.disconnect();  fail(mChildCurrentLocation, "获取文件信息错误,错误码为:" + reply, null);  return; } file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize); file.seek(mConfig.START_LOCATION); byte[] buffer = new byte[mBufSize]; int len; while ((len = is.read(buffer)) != -1) {   //如果该条线程读取的数据长度大于所分配的区间长度,则只能读到区间的最大长度  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);  } }

这里还有几个坑需要处理一下:

  1. 对于FTP客户端来说,一般需要设置被动模式,被动模式和主动模式的区别

  2. 在获取文件流后,还需要使用FTPReply.isPositivePreliminary(reply)进行第二次命令判断

关于FTP文件上传

FTP 文件断点续传的方式原理和下载的都差不多:

  1. 都是在停止的时候记录停止位置,重新开始下载的时候从指定位置通过REST命令恢复断点。

  2. 都需要在任务执行前获取文件信息,比对服务器上的文件。

而和下载有区别的是:

  1. FTP上传时需要指定工作目录、在远程服务器上创建文件夹

  2. 需要服务器给用户打开删除和读入IO的权限,否则会出现550权限错误问题

关于"Android中如何利用FTP实现多线程断点续传下载上传功能"这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对"Android中如何利用FTP实现多线程断点续传下载上传功能"知识都有一定的了解,大家如果还想学习更多知识,欢迎关注行业资讯频道。

文件 线程 服务器 服务 位置 断点 信息 区间 长度 功能 编码 路径 登录 原理 命令 客户 客户端 代码 模式 任务 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 从服务器下载文件的网页制作 r语言合并两个数据库数据集 软件工程团队作业数据库对象设计 揭西县组织网络安全民兵训练 什么是数据库死锁 数据库修改名是什么意思 广西网络技术职位表 网络安全我们应该怎么做 倩女幽魂那个服务器 杭州net软件开发多少钱 鼎湖宝盈网络技术有限公司 网络技术路线分析 绍兴市公安局网络安全保卫支队 对于网络安全应该怎样做 互联网科技企业有什么区别吗 水利部网络安全攻防演练 网络安全需要学编程吗 快快网络安全儿童画 数据库和基本表的定义总结 湖南戴尔服务器维修云空间 人力资源的数据库 软件开发笔记本电脑什么配置 公司如何保障服务器安全 华三服务器怎么检测硬盘是否正常 药智网药品价格数据库 把服务器装进笔记本 plsql中连接数据库如何填写 软件开发png图标 办公 网络安全学院开学视频 客户端服务器模型
0