鸿蒙开发

HarmonyOS开发中断点续传的简单实现

2025-02-23  本文已影响0人  MardaWang

背景:看到某技术交流群有朋友咨询断点续传是什么,怎么实现,寻思写篇短文简单介绍一下。

在应用开发中,断点续传功能通常指在文件上传或下载过程中,当因网络中断、应用崩溃等原因导致传输中断后,能够从上次中断的位置继续进行传输。以下分别从文件下载和文件上传两个方面介绍实现断点续传的方法:

文件下载断点续传

实现思路

  1. 获取文件总大小:在开始下载前,通过 HTTP 请求的响应头获取文件的总大小。
  2. 记录已下载位置:在下载过程中,不断记录已下载的字节数,并将其保存到本地文件或数据库中。
  3. 恢复下载:当需要恢复下载时,从本地读取已下载的字节数,然后在 HTTP 请求中添加 Range 头,指定从该位置开始继续下载。

代码示例

import http from '@ohos.net.http';
import fs from '@ohos.file.fs';

async function downloadFile(url: string, filePath: string) {
  let startByte = 0;
  try {
    // 检查本地文件是否存在,若存在则获取已下载的字节数
    const fileStat = await fs.stat(filePath);
    startByte = fileStat.size;
  } catch (e) {
    // 文件不存在,从头开始下载
  }

  const httpRequest = http.createHttp();
  // 设置请求头,指定从 startByte 位置开始下载
  httpRequest.setRequestHeader('Range', `bytes=${startByte}-`);

  httpRequest.request(
    url,
    {
      method: http.RequestMethod.GET,
      connectTimeout: 60000,
      readTimeout: 60000,
    },
    (err, response) => {
      if (err) {
        console.error('下载请求出错:', err);
        return;
      }

      const totalSize = parseInt(response.getHeader('Content-Length') || '0', 10) + startByte;
      const fileStream = fs.createWriteStream(filePath, { flags: startByte > 0 ? 'a' : 'w' });

      response.on('data', (chunk) => {
        startByte += chunk.length;
        fileStream.write(chunk);
        console.log(`已下载: ${startByte}/${totalSize}`);
      });

      response.on('end', () => {
        fileStream.end();
        console.log('下载完成');
      });

      response.on('error', (error) => {
        fileStream.end();
        console.error('下载过程出错:', error);
      });
    }
  );
}

// 使用示例
const downloadUrl = 'http://example.com/file.zip';
const savePath = '/data/storage/el2/base/haps/entry/files/file.zip';
downloadFile(downloadUrl, savePath);

文件上传断点续传

实现思路

  1. 记录已上传位置:在上传过程中,记录已上传的字节数,并将其保存到本地文件或数据库中。
  2. 恢复上传:当需要恢复上传时,从本地读取已上传的字节数,然后从该位置开始继续上传文件内容。

代码示例

import http from '@ohos.net.http';
import fs from '@ohos.file.fs';

async function uploadFile(url: string, filePath: string) {
  let uploadedBytes = 0;
  try {
    // 检查本地记录文件是否存在,若存在则获取已上传的字节数
    const recordFile = '/data/storage/el2/base/haps/entry/files/upload_record.txt';
    const recordStat = await fs.stat(recordFile);
    if (recordStat.size > 0) {
      const recordContent = await fs.readFile(recordFile, { encoding: 'utf-8' });
      uploadedBytes = parseInt(recordContent, 10);
    }
  } catch (e) {
    // 记录文件不存在,从头开始上传
  }

  const fileStream = fs.createReadStream(filePath, { start: uploadedBytes });
  const httpRequest = http.createHttp();

  httpRequest.request(
    url,
    {
      method: http.RequestMethod.POST,
      connectTimeout: 60000,
      readTimeout: 60000,
      extraData: fileStream,
    },
    (err, response) => {
      if (err) {
        console.error('上传请求出错:', err);
        return;
      }

      fileStream.on('data', (chunk) => {
        uploadedBytes += chunk.length;
        // 保存已上传的字节数到本地记录文件
        fs.writeFile('/data/storage/el2/base/haps/entry/files/upload_record.txt', uploadedBytes.toString(), { encoding: 'utf-8' });
        console.log(`已上传: ${uploadedBytes}`);
      });

      fileStream.on('end', () => {
        // 上传完成后删除记录文件
        fs.unlink('/data/storage/el2/base/haps/entry/files/upload_record.txt');
        console.log('上传完成');
      });

      fileStream.on('error', (error) => {
        console.error('上传过程出错:', error);
      });
    }
  );
}

// 使用示例
const uploadUrl = 'http://example.com/upload';
const filePath = '/data/storage/el2/base/haps/entry/files/file.zip';
uploadFile(uploadUrl, filePath);

注意事项

上一篇 下一篇

猜你喜欢

热点阅读