当前位置: 首页 > article >正文

HarmonyOS之深入解析如何根据url下载pdf文件并且在本地显示和预览

一、文件下载

① 网络请求配置
  • 下载在线文件,需要访问网络,因此需要在 config.json 中添加网络权限:
{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET",
        "reason": "下载文件需要网络访问"
      },
      {
        "name": "ohos.permission.READ_MEDIA",
        "reason": "访问下载文件"
      },
      {
        "name": "ohos.permission.WRITE_MEDIA",
        "reason": "保存下载文件"
      }
    ]
  }
}
② 文件下载核心代码
import http from '@ohos.net.http';

let httpRequest = http.createHttp()
    let opt: http.HttpRequestOptions = {
      method: http.RequestMethod.GET,
      header: { 'Accept-Encoding': 'gzip, deflate, br',
        'Accept-Language': 'zh-CN,zh;q=0.9',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
      },
      expectDataType: http.HttpDataType.ARRAY_BUFFER
    }

    httpRequest.request(url, opt)
      .then((resp) => {
        let respDisp: string = resp.header["content-disposition"]
        // 从文件信息提取文件名称,包含双引号
        let fileNameWithQuote = respDisp.split(";")[1].split("=")[1]
        // 去掉文件名称的双引号
        let fileName = fileNameWithQuote.substring(1, fileNameWithQuote.length - 1)
        // 保存文件到本地
        let filePath = this.saveFile(resp.result as ArrayBuffer, fileName)
        if (filePath.length > 0) {
          let msgHistory = "文件已保存到:" + filePath + "\r\n"
          toast('下载成功,可在“我的下载”中查看下载的附件')
        } else {
          toast('保存失败')
        }
      })
      .catch((e:Error) => {
        toast('下载失败')
      })
③ 保存文件到本地
import fs from '@ohos.file.fs'

// 保存文件并返回保存路径
  saveFile(buf: ArrayBuffer, fileName: string): string {
    let pathDir = getContext(this).filesDir
    let filePath = pathDir + "/" + fileName
    let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
    fs.writeSync(file.fd, buf)
    fs.closeSync(file)
    return filePath
  }

二、文件的读取

  • 在上面的文件被下载后,我们已经将文件保存到我们的本地路径中,那么该如何读取这些文件呢?
import fs from '@ohos.file.fs'

@State filesArray : MyDownloadDataModel[] = []

getListFile(): void {
	// 获取当前应用的文件目录路径
    let pathDir = getContext(this).filesDir
    // 配置文件列表的筛选选项
    let listFileOption: ListFileOptions = {
      recursion: false,  // 不递归子目录
      listNum: 0,		  // 0表示获取所有符合条件的文件
      filter: {
        suffix: [".pdf"], // 只筛选这些后缀的文件
        fileSizeOver: 0             // 文件大小超过0字节(即所有大小)
      }
    };
    // 同步获取目录下符合条件的文件列表
    let files = fs.listFileSync(pathDir, listFileOption);
    // 遍历所有匹配的文件
    for (let i = 0; i < files.length; i++) {
	   // 拼接文件的完整路径
      let filePath = pathDir + '/' + files[i]
      // 创建文件数据模型对象
      let model = new MyDownloadDataModel
      model.fileName = files[i]
      model.filePath = filePath
      model.fileType = files[i].split('.')[1]

	 // 异步获取文件大小信息
      fs.stat(filePath).then((stat: fs.Stat) => {
        // 计算文件大小(转换为MB)
        let size = stat.size / 1024 / 1024
        // 设置文件大小字符串表示(示例中实际用的是KB单位)
        model.fileSize = stat.size.toString() + "KB"
      }).catch((err: BusinessError) => {
        // 如果获取大小失败,设置默认值0
        model.fileSize = "0 KB"
      });

	  // 异步获取文件创建时间信息
      fs.lstat(filePath).then((stat: fs.Stat) => {
        // 将时间戳转换为可读格式
        model.fileCreateTime = DateRsUtil.getDateStringWithTimeStamp(stat.ctime)
        // 将完整模型对象加入数组
        this.filesArray.push(model)
      }).catch((err: BusinessError) => {
        model.fileCreateTime = ''
        this.filesArray.push(model)
      });
    }
}

三、预览文件

① 使用系统预览能力(推荐)
// 获取当前UI上下文对象(用于界面相关操作)
let uiContext = getContext(this);

// 配置预览窗口的显示参数
let displayInfo: filePreview.DisplayInfo = {
  x: 100,      // 预览窗口左上角的x坐标(单位:像素)
  y: 100,      // 预览窗口左上角的y坐标(单位:像素)
  width: 800,  // 预览窗口的宽度(单位:像素)
  height: 800  // 预览窗口的高度(单位:像素)
};

// 配置要预览的文件信息
let fileInfo: filePreview.PreviewInfo = {
  title: file.fileName,  // 设置预览窗口标题为文件名
  uri: fileUri.getUriFromPath(file.filePath),  // 将文件路径转换为URI格式
  mimeType: 'application/pdf'  // 明确指定文件类型为PDF
};

// 调用文件预览功能
filePreview.openPreview(uiContext, fileInfo, displayInfo)
  .then(() => {
    // 预览成功回调
    console.info('Succeeded in opening preview');
  })
  .catch((err: BusinessError) => {
    // 预览失败回调
    console.error(
      `Failed to open preview, 
      err.code = ${err.code},  // 错误码
      err.message = ${err.message}`  // 错误描述
    );
  });
② Web组件预览(备选)
import webview from '@ohos.web.webview';

@Component
struct PdfWebView {
  controller: webview.WebviewController = new webview.WebviewController();

  build() {
    Column() {
      Web({
        src: $rawfile('downloaded.pdf'), // 或使用file://路径
        controller: this.controller
      })
      .onPageEnd(e => {
        console.info('PDF加载完成');
      })
    }
  }
}

四、分享文件

requestShareFile(file: MyDownloadDataModel) {
    // 构造ShareData,需配置一条有效数据信息
    let data: systemShare.SharedData = new systemShare.SharedData({
      utd: utd.UniformDataType.PDF,
      content: file.fileName
    });

    let uiContext = getContext(this)
    // 获取文件的沙箱路径
    let pathInSandbox = uiContext.filesDir + file.filePath
    // 将沙箱路径转换为uri
    let uri = fileUri.getUriFromPath(pathInSandbox)
    // 添加多条记录
    data.addRecord({
      utd: utd.UniformDataType.PDF,
      uri: uri
    });
    // 构建ShareController
    let controller: systemShare.ShareController = new systemShare.ShareController(data)
    // 注册分享面板关闭监听
    controller.on('dismiss', () => {
      // 分享结束,可处理其他业务

    });
    // 进行分享面板显示
    let context = getContext(this) as common.UIAbilityContext;
    controller.show(context, {
      previewMode: systemShare.SharePreviewMode.DETAIL,
      selectionMode: systemShare.SelectionMode.SINGLE
    });
  }

五、高级功能扩展

① 断点续传
const downloadRange = (url: string, filePath: string, start: number) => {
  const file = fileio.openSync(filePath, fileio.O_RDWR);
  fileio.lseekSync(file.fd, start, fileio.SeekType.SEEK_SET);
  
  return http.request(url, {
    header: { 'Range': `bytes=${start}-` },
    file: file.fd
  });
};
② 文件缓存管理
function cleanOldPdfs(maxAge: number = 7 * 24 * 3600 * 1000) {
  const dir = fileio.opendirSync('internal://cache/');
  const now = Date.now();

  for (const entry of dir.readSync()) {
    if (entry.name.endsWith('.pdf')) {
      const stat = fileio.statSync(`internal://cache/${entry.name}`);
      if (now - stat.mtime * 1000 > maxAge) {
        fileio.unlinkSync(`internal://cache/${entry.name}`);
      }
    }
  }
}

六、注意事项

① 安全性
  • 验证下载URL的合法性;
  • 检查文件签名(如有);
  • 敏感文件建议加密存储。
② 性能优化
  • 大文件分块下载(如 10MB/块);
  • 预览前校验文件头是否为%PDF;
③ 兼容性处理
function tryOpenWithWebView(filePath: string) {
  try {
    // 尝试转换为content:// URI
    const uri = fileuri.getUriFromPath(filePath, 'content');
    // 调用系统文件选择器
    // ...
  } catch (error) {
    prompt.showToast({ message: '无法打开PDF文件' });
  }
}

http://www.kler.cn/a/611990.html

相关文章:

  • ubuntu24 部署vnc server 使用VNC Viewer连接
  • Scala基础语法和简介
  • Cent OS7+Docker+Dify
  • SpringBoot实战——详解JdbcTemplate操作存储过程
  • 第十六届蓝桥杯模拟二(串口通信)
  • 数据结构每日一题day3(顺序表)★★★★★
  • 国际机构Gartner发布2025年网络安全趋势
  • 微软KBLaM:当语言模型学会“查字典”的下一代AI革命
  • 信息系统安全保护等级详解
  • 一文读懂Python之json模块(33)
  • Axure RP设计软件中的各种函数:包括数字、数学、字符串、时间及中继器函数,详细解释了各函数的用途、参数及其应用场景。
  • SpringMVC请求与响应深度解析:从核心原理到高级实践
  • 吴恩达机器学习笔记复盘(十一)逻辑回归的代价和损失函数
  • 扭蛋机小程序开发,潮玩娱乐消费风口下的机遇
  • 右击没有Word、PPT、Excel功能
  • 蓝桥与力扣刷题(蓝桥 蓝桥骑士)
  • Centos 前准备工作
  • Rust vs. Go: 性能测试(2025)
  • 深入解析libsunrpc:构建分布式系统的核心RPC库
  • 考研408-数据结构完整代码 线性表的链式存储结构 - 单链表