• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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```