1# 应用文件访问(ArkTS) 2<!--Kit: Core File Kit--> 3<!--Subsystem: FileManagement--> 4<!--Owner: @wangke25; @gsl_1234; @wuchengjun5--> 5<!--Designer: @gsl_1234; @wangke25--> 6<!--Tester: @liuhonggang123; @yue-ye2; @juxiaopang--> 7<!--Adviser: @foryourself--> 8 9应用需要对应用文件目录下的应用文件进行查看、创建、读写、删除、移动、复制、获取属性等访问操作,下文介绍具体方法。 10 11## 接口说明 12 13开发者通过基础文件操作接口([ohos.file.fs](../reference/apis-core-file-kit/js-apis-file-fs.md))实现应用文件访问能力,主要功能如下表所示。 14 15**表1** 基础文件操作接口功能,其中“√”表示支持,“-”表示不区分同步和异步。 16 17| 接口名 | 功能 | 接口类型 | 支持同步 | 支持异步 | 18| -------- | -------- | -------- | -------- | -------- | 19| access | 检查文件是否存在 | 方法 | √ | √ | 20| close | 关闭文件 | 方法 | √ | √ | 21| copyFile | 复制文件 | 方法 | √ | √ | 22| createStream | 基于文件路径打开文件流 | 方法 | √ | √ | 23| listFile | 列出文件夹下所有文件名 | 方法 | √ | √ | 24| mkdir | 创建目录 | 方法 | √ | √ | 25| moveFile | 移动文件 | 方法 | √ | √ | 26| open | 打开文件 | 方法 | √ | √ | 27| read | 从文件读取数据 | 方法 | √ | √ | 28| rename | 重命名文件或文件夹 | 方法 | √ | √ | 29| rmdir | 删除整个目录 | 方法 | √ | √ | 30| stat | 获取文件详细属性信息 | 方法 | √ | √ | 31| unlink | 删除单个文件 | 方法 | √ | √ | 32| write | 将数据写入文件 | 方法 | √ | √ | 33| Stream.close | 关闭文件流 | 方法 | √ | √ | 34| Stream.flush | 刷新文件流 | 方法 | √ | √ | 35| Stream.write | 将数据写入流文件 | 方法 | √ | √ | 36| Stream.read | 从流文件读取数据 | 方法 | √ | √ | 37| File.fd | 获取文件描述符 | 属性 | - | - | 38| OpenMode | 设置文件打开标签 | 属性 | - | - | 39| Filter | 设置文件过滤配置项 | 类型 | - | - | 40 41> **注意:** 42> 43> 使用基础文件操作接口时,耗时较长的操作,例如:read、write等,建议使用异步接口,避免应用崩溃。 44 45## 开发示例 46 47在对应用文件开始访问前,开发者需要[获取应用文件路径](../application-models/application-context-stage.md#获取应用文件路径)。以从UIAbilityContext获取HAP级别的文件路径为例进行说明,UIAbilityContext的获取方式请参见[获取UIAbility的上下文信息](../application-models/uiability-usage.md#获取uiability的上下文信息)。 48 49下面介绍几种常用操作示例。 50 51### 新建并读写一个文件 52 53以下示例代码演示了如何新建一个文件并对其读写。 54 55```ts 56// pages/xxx.ets 57import { fileIo as fs, ReadOptions } from '@kit.CoreFileKit'; 58import { common } from '@kit.AbilityKit'; 59import { buffer } from '@kit.ArkTS'; 60 61// 请在组件内获取context,确保this.getUIContext().getHostContext()返回结果为UIAbilityContext 62let context = this.getUIContext().getHostContext() as common.UIAbilityContext; 63 64function createFile(context: common.UIAbilityContext): void { 65 let filesDir = context.filesDir; 66 // 文件不存在时创建并打开文件,文件存在时打开文件 67 let file = fs.openSync(filesDir + '/test.txt', fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); 68 // 写入一段内容至文件 69 let writeLen = fs.writeSync(file.fd, "Try to write str."); 70 console.info("The length of str is: " + writeLen); 71 // 创建一个大小为1024字节的ArrayBuffer对象,用于存储从文件中读取的数据 72 let arrayBuffer = new ArrayBuffer(1024); 73 // 设置读取的偏移量和长度 74 let readOptions: ReadOptions = { 75 offset: 0, 76 length: arrayBuffer.byteLength 77 }; 78 // 读取文件内容到ArrayBuffer对象中,并返回实际读取的字节数 79 let readLen = fs.readSync(file.fd, arrayBuffer, readOptions); 80 // 将ArrayBuffer对象转换为Buffer对象,并转换为字符串输出 81 let buf = buffer.from(arrayBuffer, 0, readLen); 82 console.info("the content of file: " + buf.toString()); 83 // 关闭文件 84 fs.closeSync(file); 85} 86``` 87 88### 读取文件内容并写入到另一个文件 89 90以下示例代码演示了如何从一个文件读写内容到另一个文件。 91 92```ts 93// pages/xxx.ets 94import { fileIo as fs, ReadOptions, WriteOptions } from '@kit.CoreFileKit'; 95import { common } from '@kit.AbilityKit'; 96 97// 请在组件内获取context,确保this.getUIContext().getHostContext()返回结果为UIAbilityContext 98let context = this.getUIContext().getHostContext() as common.UIAbilityContext; 99 100function readWriteFile(context: common.UIAbilityContext): void { 101 let filesDir = context.filesDir; 102 // 打开文件 103 let srcFile = fs.openSync(filesDir + '/test.txt', fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); 104 let destFile = fs.openSync(filesDir + '/destFile.txt', fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); 105 // 读取源文件内容并写入至目的文件 106 let bufSize = 4096; 107 let readSize = 0; 108 let buf = new ArrayBuffer(bufSize); 109 let readOptions: ReadOptions = { 110 offset: readSize, 111 length: bufSize 112 }; 113 let readLen = fs.readSync(srcFile.fd, buf, readOptions); 114 while (readLen > 0) { 115 readSize += readLen; 116 let writeOptions: WriteOptions = { 117 length: readLen 118 }; 119 fs.writeSync(destFile.fd, buf, writeOptions); 120 readOptions.offset = readSize; 121 readLen = fs.readSync(srcFile.fd, buf, readOptions); 122 } 123 // 关闭文件 124 fs.closeSync(srcFile); 125 fs.closeSync(destFile); 126} 127``` 128 129> **说明:** 130> 131> 使用读写接口时,需注意可选项参数offset的设置。对于已存在且读写过的文件,文件偏移指针默认在上次读写操作的终止位置。 132 133### 以流的形式读写文件 134 135以下示例代码演示了如何使用流接口读取test.txt的文件内容并写入到destFile.txt文件中。 136 137```ts 138// pages/xxx.ets 139import { fileIo as fs, ReadOptions } from '@kit.CoreFileKit'; 140import { common } from '@kit.AbilityKit'; 141 142// 请在组件内获取context,确保this.getUIContext().getHostContext()返回结果为UIAbilityContext 143let context = this.getUIContext().getHostContext() as common.UIAbilityContext; 144 145async function readWriteFileWithStream(context: common.UIAbilityContext): Promise<void> { 146 let filesDir = context.filesDir; 147 // 创建并打开输入文件流 148 let inputStream = fs.createStreamSync(filesDir + '/test.txt', 'r+'); 149 // 创建并打开输出文件流 150 let outputStream = fs.createStreamSync(filesDir + '/destFile.txt', "w+"); 151 152 let bufSize = 4096; 153 let readSize = 0; 154 let buf = new ArrayBuffer(bufSize); 155 let readOptions: ReadOptions = { 156 offset: readSize, 157 length: bufSize 158 }; 159 // 以流的形式读取源文件内容并写入到目标文件 160 let readLen = await inputStream.read(buf, readOptions); 161 readSize += readLen; 162 while (readLen > 0) { 163 const writeBuf = readLen < bufSize ? buf.slice(0, readLen) : buf; 164 await outputStream.write(writeBuf); 165 readOptions.offset = readSize; 166 readLen = await inputStream.read(buf, readOptions); 167 readSize += readLen; 168 } 169 // 关闭文件流 170 inputStream.closeSync(); 171 outputStream.closeSync(); 172} 173``` 174 175> **说明:** 176> 177> 使用流接口时,需注意流的及时关闭。同时流的异步接口应严格遵循异步接口使用规范,避免同步、异步接口混用。流接口不支持并发读写。 178 179### 查看文件列表 180 181以下示例代码演示了如何查看文件列表。 182 183```ts 184import { fileIo as fs, Filter, ListFileOptions } from '@kit.CoreFileKit'; 185import { common } from '@kit.AbilityKit'; 186 187// 请在组件内获取context,确保this.getUIContext().getHostContext()返回结果为UIAbilityContext 188let context = this.getUIContext().getHostContext() as common.UIAbilityContext; 189 190// 查看文件列表 191function getListFile(context: common.UIAbilityContext): void { 192 let listFileOption: ListFileOptions = { 193 recursion: false, 194 listNum: 0, 195 filter: { 196 suffix: [".png", ".jpg", ".txt"], 197 displayName: ["test*"], 198 fileSizeOver: 0, 199 lastModifiedAfter: new Date(0).getTime() 200 } 201 }; 202 let filesDir = context.filesDir; 203 let files = fs.listFileSync(filesDir, listFileOption); 204 for (let i = 0; i < files.length; i++) { 205 console.info(`The name of file: ${files[i]}`); 206 } 207} 208``` 209 210### 使用文件流 211 212以下示例代码演示了如何使用文件可读流,文件可写流。 213 214```ts 215// pages/xxx.ets 216import { fileIo as fs } from '@kit.CoreFileKit'; 217import { common } from '@kit.AbilityKit'; 218 219// 请在组件内获取context,确保this.getUIContext().getHostContext()返回结果为UIAbilityContext 220let context = this.getUIContext().getHostContext() as common.UIAbilityContext; 221 222function copyFileWithReadable(context: common.UIAbilityContext): void { 223 let filesDir = context.filesDir; 224 // 创建文件可读流 225 const rs = fs.createReadStream(`${filesDir}/read.txt`); 226 // 创建文件可写流 227 const ws = fs.createWriteStream(`${filesDir}/write.txt`); 228 // 暂停模式拷贝文件。在拷贝数据时,将原始数据暂停,然后将数据复制到另一个位置,适用于对数据完整性和一致性要求较高的场景 229 rs.on('readable', () => { 230 const data = rs.read(); 231 if (!data) { 232 return; 233 } 234 ws.write(data); 235 }); 236} 237 238function copyFileWithData(context: common.UIAbilityContext): void { 239 let filesDir = context.filesDir; 240 // 创建文件可读流 241 const rs = fs.createReadStream(`${filesDir}/read.txt`); 242 // 创建文件可写流 243 const ws = fs.createWriteStream(`${filesDir}/write.txt`); 244 // 流动模式拷贝文件。数据的读取和写入是同时进行的,不需要暂停原始数据的访问,适用于对数据实时性要求较高的场景 245 rs.on('data', (emitData) => { 246 const data = emitData?.data; 247 if (!data) { 248 return; 249 } 250 ws.write(data as Uint8Array); 251 }); 252} 253``` 254 255### 使用文件哈希流 256 257哈希流是一种数据传输和存储技术,可以将任意长度的数据转换为固定长度的哈希值来验证数据的完整性和一致性。以下代码演示了如何使用文件哈希处理接口([ohos.file.hash](../reference/apis-core-file-kit/js-apis-file-hash.md))来处理文件哈希流。 258 259```ts 260// pages/xxx.ets 261import { fileIo as fs } from '@kit.CoreFileKit'; 262import { hash } from '@kit.CoreFileKit'; 263import { common } from '@kit.AbilityKit'; 264 265// 获取应用文件路径,请在组件内获取context 266let context = this.getUIContext().getHostContext() as common.UIAbilityContext; 267 268function hashFileWithStream(context: common.UIAbilityContext) { 269 let filesDir = context.filesDir; 270 const filePath = `${filesDir}/test.txt`; 271 // 创建文件可读流 272 const rs = fs.createReadStream(filePath); 273 // 创建哈希流 274 const hs = hash.createHash('sha256'); 275 rs.on('data', (emitData) => { 276 const data = emitData?.data; 277 hs.update(new Uint8Array(data?.split('').map((x: string) => x.charCodeAt(0))).buffer); 278 }); 279 rs.on('close', async () => { 280 const hashResult = hs.digest(); 281 const fileHash = await hash.hash(filePath, 'sha256'); 282 console.info(`hashResult: ${hashResult}, fileHash: ${fileHash}`); 283 }); 284} 285 286```