文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2023-05-30 22:30

关注

Android中怎么利用FTP实现多线程断点续传下载上传功能,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

FTP下载原理

FTP单线程断点续传

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

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

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

FTP多线程断点续传

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

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

分段下载

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

功能实现

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

通过下文的几步操作,你就能很简单的实现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服务器上该路径的文件列表。

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,因此,客户端在获取文件信息时

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权限错误问题

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注编程网行业资讯频道,感谢您对编程网的支持。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯