原文:为你推荐一款高效的IO组件——okio,点击链接查看更多技术内容。

前不久,三方组件库上新了一批JS/eTS组件,其中就包括okio组件。okio是一个可应用于HarmonyOS的高效IO库,它依托于系统能力,提供字符串的编解码转换能力,基础数据类型的读写能力以及对文件读写的支持。本期将为大家介绍okio的工作原理及使用方法。

一、okio的产生背景

IO,即输入输出(Input/Output)。绝大多数应用都需要与外部进行数据交互,这就会涉及IO。系统提供了IO能力,在使用系统IO时,通常需要一个中间缓冲区来保存读取到的数据。数据先从输入流缓冲区复制到中间缓冲区,再从中间缓冲区复制到输出流缓冲区。中间多次拷贝,降低了IO效率,同时增加了系统消耗。 为了满足开发者对IO的更高要求,三方组件库推出IO处理利器——okio(JS版本)。okio使用Segment作为数据存储容器,通过提供Segment移动、共享、合并和分割的能力,让数据读写变得非常灵活,也减少了数据复制,提升了IO效率。此外,okio还通过SegmentPool对Segment进行回收和复用,减少大量创建Segment带来的系统消耗。下面就带大家深入了解JS版本的okio的工作原理,探索它是如何提升IO效率的~

二、两个基本概念

在深入解析okio的工作原理之前,我们先来了解两个基本概念:Segment和SegmentPool。

1. Segment

okio将数据分割成一块块的片段存放在Segment里面。Segment是一个数据存储的真正类,内部维护着一个大小为8192字节的字节数组用于存储数据。Segment最小可共享、可写入的数据大小为1024字节。Segment使用pos、limit、shared、owner、prev、next来分别记录读写位置、是否可写入、是否能共享、数据拥有者、前置节点和后置节点信息。Segment对外提供sharedCopy、unsharedCopy、split、push、pop、compact、writeTo等接口用于操作数据。

Segment同时拥有前置节点和后置节点,构成一个双向链表。读取数据的时候,从双向链表的头部开始读取;而写入数据的时候,从双向链表的尾部写入数据。

2. SegmentPool

为了管理Segment,okio维护了一个Segment对象池(即SegmentPool),对废弃的Segment回收、复用和内存共享,从而减少内存的申请和GC(garbage collection,垃圾收集)的频率,使性能得到优化。SegmentPool是一个由最多8个Segment组成的单链表。一个Segment的最大大小是8192字节(即8KB),所以SegmentPool的最大大小是64KB。

三、okio的工作原理

okio组件最重要的功能就是“读”和“写”。下面我们就从读写开始,了解okio的工作原理。

1. 读写数据

okio读写数据的过程中,遵循大块数据移动、小块数据复制的原则。okio从输入流读取数据到输入流缓冲区时,会先找到双向链表尾部的Segment节点,如果此节点的剩余容量足够,则直接将读取到的数据存入到此节点。如果此节点的剩余容量不足,则从SegmentPool里面取一个Segment链接到双向链表的尾部,然后将数据存入这个新节点。okio从输入流缓冲区读取数据,再写入数据到输出流缓冲区。这个过程比较复杂,有以下几种情况:

(1) 从输入流缓冲区获取到Segment,如果数据是满的(字节数组data长度为8092字节),那么直接修改此Segment的prev和next信息,将其添加到输出流缓冲区的双向链表的尾部,省去一次数据复制过程。

图1 大块数据移动

(2) 从输入流缓冲区获取到Segment(假设为Segment1),如果数据不是满的,可以通过pos和limit信息来确定segment1的可读数据,再和输出流缓冲区的双向链表的尾部节点(假设为Segment2)的剩余容量进行对比: 如果Segment1的可读数据比Segment2的剩余容量小,则把Segment1的数据复制到Segment2,然后回收Segment1到SegmentPool。如果Segment1的可读数据比Segment2的剩余容量大,那么直接修改Segment1的prev和next信息,将其添加到Segment2的后面。

(3) 从输入流缓冲区获取到Segment(假设为Segment3),如果只需要传递部分数据(比如总数据为4096字节,只传递1024字节),okio会通过split接口将Segment3拆分成含3072字节数据的Segment3-1和含1024字节数据的Segment3-2,然后按照(2)的逻辑将Segment3-2的数据写入输出流缓冲区。

图2 Segment拆分

拆分Segment的时候,可以通过参数指定拆分后的第一个Segment含有的未读字节数(byteCount)。拆分后,第一个Segment包含的数据范围是[pos,pos+byteCount),第二个Segment包含的数据范围是[pos+byteCount,limit)。拆分Segment时也遵循大块数据移动、小块数据复制的原则。当byteCount大于1024时,使用共享的Segment,否则复制数据。(注:文件、流、socket相关的IO优化需要系统支持,待后续版本优化提供。) 2. Segment的回收与复用

接下来,我们再来看看SegmentPool是如何回收和复用Segment的。

每次okio想要使用Segment就从SegmentPool中获取,使用完毕后又会放回到SegmentPool中等待复用,核心方法为take()和recycle()。

(1) take()方法

take()方法负责从对象池单链表的头部获取可以使用的Segment。如果获取不到,说明单链表是空的,此时新创建一个Segment给缓冲区使用。如果能获取到,则取出单链表的头部节点,再将下一个节点置为单链表的头部节点,并将取出来的Segment的next置空,同时更新对象池大小。

(2) recycle()方法

recycle()方法负责回收缓冲区里面使用完毕的Segment。回收开始时,首先更新对象池大小,然后把回收对象Segment添加到单链表头部,接着重置Segment的pos和limit为0。注意,以下情况不会回收Segment:

  • 当前Segment的prev和next不为空

  • 当前Segment是共享的

  • 对象池已经有8个Segment了

3. 字符串处理

除了Segment和SegmentPool外,okio还封装了ByteString类来进行字符串处理。ByteString提供Base64编解码、utf-8编码、十六进制编解码、大小写转换、内容比较等丰富的API,可以很方便地处理字符串。在进行字符串处理时,由于ByteString同时持有原始字符串和对应的字节数组,可以直接使用字节数组里面的数据进行操作,不需要先将字符串转换为字节数组。特别是在频繁转换编码的场景下,通过这种以空间换时间的方式,可以避免字符串与字节数组的多次转换,减少了时间和系统性能消耗。

四、okio的使用及示例

1. 前置配置 步骤一:在entry 的package.json文件中添加以下依赖项。

"dependencies": {"okio": "^1.0.0"}

步骤二:配置仓库镜像地址。

npm config set @ohos:registry=https://repo.harmonyos.com/npm/

步骤三:DevEco Studio的Terminal里面输入以下命令下载源代码。

cd entrynpm
install @ohos/okio

步骤四:文件的头部引入okio库。

import okio from '@ohos/okio';

步骤五:在config.json文件中申请存储权限。

"reqPermissions": [{"name": "ohos.permission.WRITE_USER_STORAGE", //写入用户存储的权限"reason": "Storage","usedScene": {"when": "always","ability": ["com.example.okioapplication.MainAbility"]}}, {"name": "ohos.permission.READ_USER_STORAGE", //读取用户存储的权限"reason": "Storage","usedScene": {"when": "always","ability": ["com.example.okioapplication.MainAbility"]}}, {"name": "ohos.permission.WRITE_EXTERNAL_MEDIA_MEMORY", //写入外部存储的权限"reason": "Storage","usedScene": {"when": "always","ability": ["com.example.okioapplication.MainAbility"]}}]}

2. 代码实现执行完上面的配置操作后,就可以进入代码编写阶段了。开发者可以使用okio提供的丰富的API接口来实现功能。下面为大家展示四个实现示例,供大家参考学习。

示例1:文件写入和读取

本示例通过sink将内容写入文件,通过source从文件读取内容。代码如下:

//通过sink将内容写入文件
var sink = new okio.Sink(this.fileUri);
sink.write(this.Value,false);
//通过source从文件读取内容
var source = new okio.Source(this.fileUri);
source.read().then(function (data) {
context.readValue = data;}).catch(function (error){console.log("error=>"+error);});

示例2:Base64解码

本示例通过ByteString实现Base64解码功能,代码如下:

let byteStringObj = new okio.ByteString.ByteString(''); //生成ByteString对象
let decodeBase64 = byteStringObj.decodeBase64('SGVsbG8gd29ybGQ='); //解码Base64字符串 this.decodeBase64Value = JSON.stringify(decodeBase64); //显示解码结果

示例3:十六进制解码

本示例通过ByteString实现十六进制解码功能,代码如下:

let byteStringObj = new okio.ByteString.ByteString('');
let decodehex = byteStringObj.decodeHex('48656C6C6F20776F726C640D0A');
this.decodeHexValue = JSON.stringify(decodehex);

示例4:Utf8编码

本示例通过ByteString实现Utf8编码功能,代码如下:

let byteStringObj = new okio.ByteString.ByteString('');
let encodeUtf8 = byteStringObj.encodeUtf8('Hello world #4 ❤ ( ͡ㆆ ͜ʖ ͡ㆆ)'); this.encodeUtf8Value = JSON.stringify(encodeUtf8);

本期okio组件就为大家介绍到这里了。okio组件已开源,欢迎大家参与贡献。

开源地址如下:

https://gitee.com/openharmony-tpc/okio

为你推荐一款高效的IO组件——okio相关推荐

  1. 推荐几款高效的Python文本编辑器!

    我们都知道程序员花费大量的时间在编写.阅读和编辑代码上,因此一定要使用高效的文本编辑器才能够提高并很好的完成工作的效率和保证工作的质量. 什么是高效的文本编辑器呢?除了自己用的得心应手外,小U认为还应 ...

  2. 轻松无广告:推荐一款高效提醒软件

    很多人的工作非常繁忙,每天需要参加各种会议.约见客户以及处理各种工作任务.在这样快节奏的工作环境中,如何确保能够高效地完成工作并不漏掉任何重要的待办事项?使用提醒软件是一个很好的解决方法. 但是,市面 ...

  3. 推荐5款高效的国产软件,精挑细选让你眼前一亮

    一眨眼推荐系列已经做了两个星期了,收获了不少好评,我也会继续保持的,只为那一句话:赠人玫瑰,手留余香. 1.网速监控--TrafficMonitor 这是一款轻量的电脑网速监控软件,我们在下载文件的时 ...

  4. 推荐5款高效办公软件,可以大幅度提升工作效率

    人类与99%的动物之间最大差别在于是否会运用工具,借助好的工具,能提升几倍的工作效率. 1.待办任务管理--Todoist 感觉自己每天事情都很多,忙起来没有方向又没有重点,一天到头也不知道做了什么? ...

  5. 抖音视频拼接怎么做?推荐一款高效实用的软件

    抖音视频拼接怎么做?可以用手机里已有的软件,如果想要方便又快捷的处理抖音视频拼接的话,可以先用万兴喵影把视频拼接好,再在抖音里使用哦! 其实对于万兴喵影来说,拼接视频只是最基础的操作之一,只要在在官网 ...

  6. 程序员的“灵魂笔记本“:五款高效笔记软件推荐

    大家好,我是 jonssonyan.作为一名程序员,我们经常需要记录和整理大量的代码.知识和项目信息,以便在日后能够高效地进行查阅和复用.而好用的笔记软件则成为了我们的"灵魂笔记本" ...

  7. 5款高效的原型设计工具

    设计并不是随心所欲,也不是每时每刻都需要创意.你需要一个向导为你指明方向- 这就是原型. 什么是原型? 原型可以概括的说是整个产品面市之前的一个框架设计.设计师可以利用它引导每个人都参与到项目中来.原 ...

  8. 小程序源码提取工具_小程序一款高效的视频声音提取和识别工具!

    编注:小程序系列面向正在使用Android.iOS.iPad OS.PC.Mac平台设备的朋友.无需单独下载App,在微信中直接打开就可以使用,即用即走,帮你更高效的完成一些事情! 给大家推荐一款高效 ...

  9. 5款高效软件推荐,每一款都是良心之作

    好用的办公软件可以帮助我们提升工作效率,和拖延症说拜拜.下面给大家分享5款高效软件,每一款都是良心之作! wolai我来 如果你发现自己常常浪费时间在寻找已保存的文件数据上,那么可以尝试构建一个个人信 ...

最新文章

  1. 人月神话贯彻执行_DNF:希洛克团本真有那么难吗?没有神话都不够格进团?_电竞...
  2. encodingaeskey java,消息体签名与加解密-开发者QA
  3. 调试安装php源码,Xdebug的安装与配置,帮助调试PHP程序
  4. linux打包压缩文件并命名,linux下如何将文件打包、压缩并分割成制定大小
  5. 单片机之串行通信接口遇到的问题
  6. 【Firewalld(Iptables)】
  7. vue 实现12个月的平铺式日历插件
  8. 沃德天,Python竟然还能做实时翻译
  9. java实现文章伪原创_网站伪原创的方法 - 百度搜狗360神马网站快速排名 - OSCHINA - 中文开源技术交流社区...
  10. aspen怎么做灵敏度分析_灵敏度分析 aspen
  11. 惠斯特电桥平衡条件的证明
  12. swagger2报错Illegal DefaultValue null for parameter type integer
  13. iterative-mergesort
  14. 【CSDN软件工程师能力认证学习精选】Python可视化库
  15. java perm 查看_JVM 分析工具和查看命令,超详细
  16. windows 服务程序和桌面程序集成(一)
  17. linux用户层通过spi读写cpld
  18. wss数据的获取与请求
  19. 谁需要,可以去微软注册@Live.com的邮箱
  20. 客户关系应该如何管理?

热门文章

  1. 那些年我在兄弟连学的PHP
  2. Java树形菜单的构建、遍历以及获取树形菜单的Id集合List
  3. 均匀分布的期望与方差计算公式
  4. LAMPSECURITY: CTF8-20220522
  5. PCI DSS安全评估简介
  6. 精读《web reflow》
  7. html中字号调节,设置页面字体大小 怎么调整ps界面字体的大小
  8. amazon mechanical turk介绍
  9. JVM内存模型JVM内存模型
  10. 瓷砖铺贴方法_5种常见的瓷砖铺贴以及施工方法介绍