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

news2025/4/2 7:12:20

一、文件下载

① 网络请求配置
  • 下载在线文件,需要访问网络,因此需要在 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.coloradmin.cn/o/2325353.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HTML5贪吃蛇游戏开发经验分享

HTML5贪吃蛇游戏开发经验分享 这里写目录标题 HTML5贪吃蛇游戏开发经验分享项目介绍技术栈核心功能实现1. 游戏初始化2. 蛇的移动控制3. 碰撞检测4. 食物生成 开发心得项目收获后续优化方向结语 项目介绍 在这个项目中&#xff0c;我使用HTML5 Canvas和原生JavaScript实现了一…

QSettings用法实战(相机配置文件的写入和读取)

很多情况&#xff0c;在做项目开发的时候&#xff0c;将参数独立出来是比较好的方法 例如&#xff1a;相机的曝光次数、曝光时长等参数&#xff0c;独立成ini文件&#xff0c;用户可以在外面修改即可生效&#xff0c;无需在动代码重新编译等工作 QSettings便可以实现该功能 内…

机器学习——集成学习框架(GBDT、XGBoost、LightGBM、CatBoost)、调参方法

一、集成学习框架 对训练样本较少的结构化数据领域&#xff0c;Boosting算法仍然是常用项 XGBoost、CatBoost和LightGBM都是以决策树为基础的集成学习框架 三个学习框架的发展是&#xff1a;XGBoost是在GBDT的基础上优化而来&#xff0c;CatBoost和LightGBM是在XGBoost的基础上…

[蓝桥杯 2023 省 A] 网络稳定性

题目来自DOTCPP&#xff1a; 思路&#xff1a; ①由于题目没有告诉我们成树形结构&#xff0c;可能成环。因此&#xff0c;我们要自己构建树。 ②本体我们通过kruskal重构树&#xff0c;按边权从大到小排序&#xff0c;那么查询的两个点的最近公共祖先权值就是答案。 ③在通…

鸿蒙项目源码-天气预报app-原创!原创!原创!

鸿蒙天气预报项目源码包运行成功含文档ArkTS语言。 我半个月写的原创作品&#xff0c;请尊重原创。 原创作品&#xff0c;盗版必究&#xff01;&#xff01;&#xff01;&#xff01; 原创作品&#xff0c;盗版必究&#xff01;&#xff01;&#xff01;&#xff01; 原创作品…

一文聊聊接入钉钉H5微应用系统实现免登操作技术思路实现验证

一文聊聊接入钉钉H5微应用系统实现免登操作技术思路实现验证 如何创建钉钉应用实现H5端免登录创建钉钉内部应用1.进入钉钉开放平台&#xff0c;配置自己的应用信息2.配置应用相关信息&#xff08;建议选择旧版&#xff0c;后续有一个token获取&#xff0c;新版会提示URL不安全&…

测试开发-定制化测试数据生成(Python+jmeter+Faker)

实现步骤 步骤一&#xff1a;使用pythonfaker随机生成测试数据 在python中开发脚本&#xff0c;随机生成所需要的数据。import json from faker import Faker faker Faker(locale"zh_CN")def generate_faker_user():return {"name" : faker.name(),&qu…

智能体开发平台与大模型关系图谱

架构层级分解(以飞速灵燕智能体平台为例)动态交互流程 3. 关键连接点说明 4. 典型数据流示例

LinuxTCP/UDP基础概念

TCP&#xff08;传输控制协议&#xff09; TCP 是一种面向连接的、可靠的、基于字节流的传输层通信协议。它的主要特点包括&#xff1a; 面向连接&#xff1a;在传输数据之前&#xff0c;需要通过“三次握手”建立连接&#xff1b;传输结束后&#xff0c;通过“四次挥手”断开…

【百日精通 JAVA | SQL篇 | 第一篇】初识数据库

一、数据库是什么&#xff1f; 数据库是一类软件&#xff0c;数据库的作用用于管理系统(这是一款成品软件&#xff0c;内部应用了很多数据结构)。 二、数据库分为两大类 1.关系型数据库 对于数据的要求比较严格 通常是以表格的方式来组织数据的。(和Excel差不多) 典型代表…

大数据Spark(五十六):Spark生态模块与运行模式

文章目录 Spark生态模块与运行模式 一、Spark生态模块 二、Spark运行模式 Spark生态模块与运行模式 一、Spark生态模块 Spark 生态模块包括&#xff1a;SparkCore、SparkSQL、SparkStreaming、StructuredStreaming、MLlib 和 GraphX。与 Hadoop 相关的整个技术生态如下所示…

Gossip协议:分布式系统中的“八卦”传播艺术

目录 一、 什么是Gossip协议&#xff1f;二、 Gossip协议的应用 &#x1f4a1;三、 Gossip协议消息传播模式详解 &#x1f4da;四、 Gossip协议的优缺点五、 总结&#xff1a; &#x1f31f;我的其他文章也讲解的比较有趣&#x1f601;&#xff0c;如果喜欢博主的讲解方式&…

Oracle初识:登录方法、导入dmp文件

目录 一、登录方法 以sys系统管理员的身份登录 &#xff0c;无需账户和密码 以账户密码的用户身份登录 二、导入dmp文件 方法一&#xff1a;PLSQL导入dmp文件 一、登录方法 Oracle的登录方法有两种。 以sys系统管理员的身份登录 &#xff0c;无需账户和密码 sqlplus / a…

微服务架构中的精妙设计:环境和工程搭建

一.前期准备 1.1开发环境安装 Oracle从JDK9开始每半年发布⼀个新版本, 新版本发布后, ⽼版本就不再进⾏维护. 但是会有⼏个⻓期维护的版本. ⽬前⻓期维护的版本有: JDK8, JDK11, JDK17, JDK21 在 JDK版本的选择上&#xff0c;尽量选择⻓期维护的版本. 为什么选择JDK17? S…

【Yolov8部署】 VS2019+opencv-dnn CPU环境下部署目标检测模型

文章目录 前言一、导出yolov8模型为onnx文件二、VS2019配置及opencv环境配置三、opencv部署总结 前言 本文主要研究场景为工业场景下&#xff0c;在工控机与工业相机环境中运行的视觉缺陷检测系统&#xff0c;因此本文主要目的为实现c环境下&#xff0c;将yolov8已训练好的检测…

3.30学习总结 Java包装类+高精度算法+查找算法

包装类&#xff1a; 基本数据类型对应的引用数据类型。 基本数据类型&#xff1a;在内存中记录的是真实的值。 八种包装类的父类都是Object类。 对象之间不能直接进行计算。 JDK5之后可以把int和integer看成一个东西&#xff0c;因为会进行内部优化。自动装箱和自动拆箱。 …

3月30号

// 1.toString 返回对象的字符串表示形式Object objnew Object();String str1obj.toString();System.out.println(str1);//java.lang.Objectb4c966a// 核心逻辑: // 当我们打印一个对象的时候,底层会调用对象的toString方法,把对象变成字符串 // 然…

Java——输入,循环,BigInteger,拷贝,排序

读取输入 打印输出到“ 标准输出流”&#xff08;即控制台窗口&#xff09;是一件非常容易的事情&#xff0c;只要 调用System.out.println 即可。然而&#xff0c;读取“ 标准输人流” System.in就没有那么简单了。要想通 过控制台进行输人&#xff0c;首先需要构造一个Scann…

Elasticsearch客户端工具初探--kibana

1 Kibana简介 Kibana是Elastic Stack&#xff08;ELK&#xff09;中的可视化工具&#xff0c;用于对Elasticsearch中存储的数据进行搜索、分析和可视化展示。它提供了直观的Web界面&#xff0c;支持日志分析、业务监控、数据探索等功能&#xff0c;广泛应用于运维监控、安全分析…

ollama在win10安装、使用、卸载

目录 前置&#xff1a; 1 下载ollama 2 安装 3 配置环境变量&#xff0c;设置模型存储位置 4 使用 5 卸载 前置&#xff1a; 1 在打算安装ollama之前&#xff0c;需要先检查电脑当前状态是否能使用ollama。确认条件满足再进行安装操作。 2 https://github.com/ollama/…