npm package: @luqi_test/cordova-plugin-file
Description: Cordova file Plugin
Author: Huawei Device, Inc. Ltd. and
Latest version: 8.1.3

# cordova-plugin-file

一款 Cordova 插件，提供完善的文件 API，支持对设备本地文件系统中的文件和目录进行读写操作。该插件遵循 [W3C](https://www.w3.org/TR/FileAPI/)[ 文件 A](https://www.w3.org/TR/FileAPI/)[PI 规](https://www.w3.org/TR/FileAPI/)[范](https://www.w3.org/TR/FileAPI/)，并提供平台特定扩展以适配不同系统的文件系统特性，本文档主要说明该插件在HarmonyOS系统中的应用。


## 安装

```bash
#安装hcordova
npm install -g hcordova
```

### 通过 hcordova 安装（推荐）

```bash
#全平台安装
hcordova plugin add cordova-plugin-file

#指定鸿蒙平台安装
hcordova plugin add cordova-plugin-file --platform ohos
```

### 通过 Git 安装

直接从 GitCode 仓库安装最新开发版本：

```bash
hcordova plugin add https://gitcode.com/OpenHarmony-Cordova/cordova-plugin-file.git --platform ohos
```

### 卸载

```bash
#全平台卸载
hcordova plugin remove cordova-plugin-file

#指定OHOS平台卸载
hcordova plugin remove cordova-plugin-file --platform ohos
```

## 文件系统结构

不同平台拥有独特的文件系统结构。该插件通过 `cordova.file` 对象提供标准化 URL，用于跨平台访问常用目录。

### `cordova.file` 对象参考


| Cordova 目录常量                                    | 鸿蒙目录路径                     |
| -------------------------------------------------- | ------------------------------ |
| `cordova.file.applicationDirectory`                | `/data/storage/el2`            |
| `cordova.file.applicationStorageDirectory`         | `/data/storage/el2/base/files` |
| `cordova.file.dataDirectory`                       | `/data/storage/el2/base/files` |
| `cordova.file.cacheDirectory`                      | `/data/storage/el2/base/cache` |
| `cordova.file.externalApplicationStorageDirectory` | `/data/storage/el2/base/files` |
| `cordova.file.externalDataDirectory`               | `/data/storage/el2/base/files` |
| `cordova.file.externalRootDirectory`               | `/data/storage/el2`            |
| `cordova.file.tempDirectory`                       | `/data/storage/el2/base/temp`  |
| `cordova.file.syncedDataDirectory`                 | `/data/storage/el2/base/files` |
| `cordova.file.documentsDirectory`                  | `/data/storage/el2/base/files` |
| `cordova.file.sharedDirectory`                     | `/data/storage/el2/base/files` |


| Cordova 目录常量             |常量值 | 鸿蒙内部目录路径                     |
| --------------------------|--| ------------------------------ |
| `LocalFileSystem.TEMPORARY`| 0 | `/data/storage/el2/base/temp`            |
| `LocalFileSystem.PERSISTENT`| 1 | `/data/storage/el2/base/files` |

## 核心概念

### 关键实体



1. `FileSystem`：表示已挂载的文件系统（如持久化存储或临时存储）

2. `DirectoryEntry`：表示文件系统中的目录（提供文件 / 目录操作方法）

3. `FileEntry`：表示文件系统中的文件（提供文件内容读写方法）

4. `File`：包含文件元数据（大小、类型、最后修改时间）和原始内容

5. `FileWriter`：向 `FileEntry` 写入内容（支持追加、截断和定位操作）

6. `FileReader`：从 `File` 读取内容（支持文本、二进制和数据 URL 格式）

### 文件系统类型



* `LocalFileSystem.PERSISTENT`：持久化存储（应用重启 / 更新后数据保留；部分平台需用户授权）

* `LocalFileSystem.TEMPORARY`：临时存储（系统空间不足时可能清理；无需授权）

## API 说明

### 1. 文件系统初始化

#### `window.requestFileSystem(type, size, successCallback, errorCallback)`

请求访问指定类型和大小的文件系统。



| 参数                | 类型 | 描述                                                         |
| ----------------- | -- | ---------------------------------------------------------- |
| `type`            | 数字 | `LocalFileSystem.PERSISTENT` 或 `LocalFileSystem.TEMPORARY` |
| `size`            | 数字 | 配额大小（单位：字节） ，通常情况此参数忽略，默认传0                   |
| `successCallback` | 函数 | 成功时调用，参数为 `FileSystem` 对象                                  |
| `errorCallback`   | 函数 | 失败时调用，参数为 `FileError` 对象                                   |

**示例**：



```javascript
// 请求持久化存储
window.requestFileSystem(
  LocalFileSystem.PERSISTENT,
  0,
  (fs) => {
    console.log(`文件系统已打开：${fs.name}（根目录：${fs.root.fullPath}）`);
    // 使用 fs.root（DirectoryEntry 对象）进行后续操作
  },
  (error) => {
    console.error(`打开文件系统失败：${getErrorMessage(error)}`);
  }
);
```

#### `window.resolveLocalFileSystemURL(url, successCallback, errorCallback)`

将本地文件系统 URL（如 `cordova.file` 常量中的 URL）解析为 `DirectoryEntry` 或 `FileEntry` 对象。


| 参数                | 类型  | 描述                                          |
| ----------------- | --- | ------------------------------------------- |
| `url`             | 字符串 | 本地文件系统 URL（例如 `cordova.file.dataDirectory`） |
| `successCallback` | 函数  | 成功时调用，参数为 `DirectoryEntry` 或 `FileEntry` 对象 |
| `errorCallback`   | 函数  | 失败时调用，参数为 `FileError` 对象                    |

**示例**：

```javascript
// 将数据目录 URL 解析为 DirectoryEntry 对象
window.resolveLocalFileSystemURL(
  cordova.file.dataDirectory,
  (dirEntry) => {
    console.log(`已解析目录：${dirEntry.name}（路径：${dirEntry.fullPath}）`);
  },
  (error) => {
    console.error(`解析 URL 失败：${getErrorMessage(error)}`);
  }
);
```

### 2. 目录操作

所有目录操作均通过 `DirectoryEntry` 对象的方法实现。

#### 创建目录

`dirEntry.getDirectory(name, options, successCallback, errorCallback)`



| 参数        | 类型  | 描述                                                                   |
| --------- | --- | -------------------------------------------------------------------- |
| `name`    | 字符串 | 要创建 / 获取的目录名称                                                        |
| `options` | 对象  | `{ create: 布尔值, exclusive: 布尔值 }`（create：不存在时是否创建；exclusive：存在时是否报错） |

**示例**：



```javascript
function createAppDirectory(directoryName) {
  window.resolveLocalFileSystemURL(
    cordova.file.dataDirectory,
    (rootDir) => {
      // 目录不存在时创建
      rootDir.getDirectory(
        directoryName,
        { create: true, exclusive: false },
        (newDir) => {
          console.log(`目录已创建：${newDir.fullPath}`);
        },
        (error) => console.error(`创建目录失败：${getErrorMessage(error)}`)
      );
    },
    (error) => console.error(`解析根目录失败：${getErrorMessage(error)}`)
  );
}

// 使用：在数据目录中创建 "app_data" 目录
createAppDirectory("app_data");
```

#### 列出目录内容

`dirEntry.createReader()` → `DirectoryReader.readEntries(successCallback, errorCallback)`

**示例**：

```javascript
function listDirectoryContents(directoryURL) {
  window.resolveLocalFileSystemURL(
    directoryURL,
    (dirEntry) => {
      const dirReader = dirEntry.createReader();
      dirReader.readEntries(
        (entries) => {
          if (entries.length === 0) {
            console.log("目录为空");
            return;
          }
          entries.forEach((entry) => {
            const entryType = entry.isFile ? "文件" : "目录";
            console.log(`${entry.name}（${entryType}）- 路径：${entry.fullPath}`);
          });
        },
        (error) => console.error(`读取目录失败：${getErrorMessage(error)}`)
      );
    },
    (error) => console.error(`解析目录失败：${getErrorMessage(error)}`)
  );
}

// 使用：列出数据目录的内容
listDirectoryContents(cordova.file.dataDirectory);
```

#### 删除目录

`dirEntry.remove(successCallback, errorCallback)`
**示例**：

```javascript
function deleteEmptyDirectory(directoryName) {
  window.resolveLocalFileSystemURL(
    cordova.file.dataDirectory + directoryName,
    (dirEntry) => {
      dirEntry.remove(
        () => console.log(`目录已删除：${directoryName}`),
        (error) => console.error(`删除目录失败：${getErrorMessage(error)}`)
      );
    },
    (error) => console.error(`目录不存在：${getErrorMessage(error)}`)
  );
}

// 使用：删除 "old_data" 目录（必须为空）
deleteEmptyDirectory("old_data");
```

### 3. 文件操作

所有文件操作均通过 `FileEntry` 对象的方法实现。

#### 创建文件

`dirEntry.getFile(name, options, successCallback, errorCallback)`



| 参数        | 类型  | 描述                                             |
| --------- | --- | ---------------------------------------------- |
| `name`    | 字符串 | 要创建 / 获取的文件名称                                  |
| `options` | 对象  | `{ create: 布尔值, exclusive: 布尔值 }`（与目录操作参数含义相同） |

**示例**：

```javascript
function createNewFile(fileName) {
  window.resolveLocalFileSystemURL(
    cordova.file.dataDirectory,
    (rootDir) => {
      rootDir.getFile(
        fileName,
        { create: true, exclusive: false },
        (fileEntry) => {
          console.log(`文件已创建：${fileEntry.name}（路径：${fileEntry.fullPath}）`);
        },
        (error) => console.error(`创建文件失败：${getErrorMessage(error)}`)
      );
    },
    (error) => console.error(`解析根目录失败：${getErrorMessage(error)}`)
  );
}

// 使用：在数据目录中创建 "user_settings.txt" 文件
createNewFile("user_settings.txt");
```

#### 写入文件

`fileEntry.createWriter(successCallback, errorCallback)` → `FileWriter.write(blob)`

**示例（文本内容）**：


```javascript
function writeTextToFile(fileName, content) {
  window.resolveLocalFileSystemURL(
    cordova.file.dataDirectory,
    (rootDir) => {
      rootDir.getFile(
        fileName,
        { create: true, exclusive: false },
        (fileEntry) => {
          fileEntry.createWriter(
            (fileWriter) => {
              // 写入完成回调
              fileWriter.onwriteend = () => {
                console.log(`成功写入文件：${fileName}`);
              };
              // 写入错误回调
              fileWriter.onerror = (error) => {
                console.error(`写入失败：${getErrorMessage(error)}`);
              };
              // 将文本转换为 Blob（支持 UTF-8 编码）
              const textBlob = new Blob([content], { type: "text/plain;charset=utf-8" });
              fileWriter.write(textBlob);
            },
            (error) => console.error(`创建写入器失败：${getErrorMessage(error)}`)
          );
        },
        (error) => console.error(`获取文件失败：${getErrorMessage(error)}`)
      );
    },
    (error) => console.error(`解析根目录失败：${getErrorMessage(error)}`)
  );
}

// 使用：将用户偏好设置写入 "user_settings.txt"
const userSettings = JSON.stringify({ theme: "dark", notifications: true });
writeTextToFile("user_settings.txt", userSettings);
```

**示例（二进制内容 - 如图片）**：


```javascript
async function writeBinaryToFile(fileName, binaryData) {
  try {
    const rootDir = await new Promise((resolve, reject) => {
      window.resolveLocalFileSystemURL(cordova.file.dataDirectory, resolve, reject);
    });
    const fileEntry = await new Promise((resolve, reject) => {
      rootDir.getFile(fileName, { create: true, exclusive: false }, resolve, reject);
    });
    const fileWriter = await new Promise((resolve, reject) => {
      fileEntry.createWriter(resolve, reject);
    });
    fileWriter.onwriteend = () => {
      console.log(`二进制数据已写入：${fileName}`);
    };
    fileWriter.onerror = (error) => {
      throw new Error(`二进制写入失败：${getErrorMessage(error)}`);
    };

    // 假设 binaryData 是 ArrayBuffer 或 Uint8Array 类型
    const binaryBlob = new Blob([binaryData], { type: "application/octet-stream" });
    fileWriter.write(binaryBlob);
  } catch (error) {
    console.error(`二进制文件操作失败：${error.message}`);
  }
}

// 使用：将图片（ArrayBuffer 类型）写入 "profile_pic.png"
// fetchImageAsArrayBuffer().then(buffer => writeBinaryToFile("profile_pic.png", buffer));
```

#### 读取文件

`fileEntry.file(successCallback, errorCallback)` → `FileReader.readAs*()`

支持的读取格式：

* `readAsText(file)`：以 UTF-8 文本格式读取

* `readAsDataURL(file)`：以 base64 编码的 data URL 格式读取（适用于图片）

* `readAsArrayBuffer(file)`：以二进制 ArrayBuffer 格式读取

* `readAsBinaryString(file)`：以原始二进制字符串格式读取（已废弃）

**示例（读取文本）**：

```javascript
function readTextFromFile(fileName) {
  window.resolveLocalFileSystemURL(
    cordova.file.dataDirectory + fileName,
    (fileEntry) => {
      fileEntry.file(
        (file) => {
          const fileReader = new FileReader();
          fileReader.onloadend = () => {
            const fileContent = fileReader.result;
            console.log(`文件内容（${fileName}）：`, fileContent);
            // 处理内容（如解析 JSON）
            try {
              const parsedData = JSON.parse(fileContent);
              console.log("解析后的 JSON 数据：", parsedData);
            } catch (e) {
              console.log("内容非 JSON 格式：", fileContent);
            }
          };
          fileReader.onerror = (error) => {
            console.error(`读取失败：${getErrorMessage(error)}`);
          };

          // 以文本格式读取文件
          fileReader.readAsText(file);
        },
        (error) => console.error(`访问文件失败：${getErrorMessage(error)}`)
      );
    },
    (error) => console.error(`文件不存在：${getErrorMessage(error)}`)
  );
}

// 使用：读取 "user_settings.txt" 文件
readTextFromFile("user_settings.txt");
```

#### 删除文件

`fileEntry.remove(successCallback, errorCallback)`

**示例**：


```javascript
function deleteFile(fileName) {
  window.resolveLocalFileSystemURL(
    cordova.file.dataDirectory + fileName,
    (fileEntry) => {
      fileEntry.remove(
        () => console.log(`文件已删除：${fileName}`),
        (error) => console.error(`删除文件失败：${getErrorMessage(error)}`)
      );
    },
    (error) => console.error(`文件不存在：${getErrorMessage(error)}`)
  );
}

// 使用：删除 "old_logs.txt" 文件
deleteFile("old_logs.txt");
```

### 4. 错误处理

所有 API 方法失败时都会返回 `FileError` 对象，可通过 `code` 属性识别错误类型。

#### `FileError` 错误码参考


| 错误码常量                                   | 值  | 描述                         |
| --------------------------------------- | -- | -------------------------- |
| `FileError.NOT_FOUND_ERR`               | 1  | 文件或目录不存在                   |
| `FileError.SECURITY_ERR`                | 2  | 安全限制（如权限不足）                |
| `FileError.ABORT_ERR`                   | 3  | 操作被用户或系统中止                 |
| `FileError.NOT_READABLE_ERR`            | 4  | 文件或目录不可读                   |
| `FileError.ENCODING_ERR`                | 5  | 编码错误（如 URL 格式无效）           |
| `FileError.NO_MODIFICATION_ALLOWED_ERR` | 6  | 不允许修改（如只读目录）               |
| `FileError.INVALID_STATE_ERR`           | 7  | 状态无效（如向已关闭的 FileWriter 写入） |
| `FileError.SYNTAX_ERR`                  | 8  | 语法错误（如文件名无效）               |
| `FileError.INVALID_MODIFICATION_ERR`    | 9  | 修改无效（如跨文件系统移动目录）           |
| `FileError.QUOTA_EXCEEDED_ERR`          | 10 | 存储配额超出                     |

#### 错误信息辅助函数

```javascript
function getErrorMessage(error) {
const errorMessages = {
  1: "文件或目录不存在",
  2: "安全错误（权限不足）",
  3: "操作已中止",
  4: "文件/目录不可读",
  5: "编码错误（URL 无效）",
  6: "不允许修改（只读）",
  7: "状态无效（如写入器已关闭）",
  8: "语法错误（文件名无效）",
  9: "修改无效（跨文件系统）",
  10: "存储配额超出"
};
return errorMessages[error.code] || `未知错误（错误码：${error.code}）`;
}
```

## 使用示例

### 示例 1：保存和加载用户偏好设置

```javascript
// 将偏好设置保存到 JSON 文件
function savePreferences(preferences) {
  const jsonContent = JSON.stringify(preferences, null, 2);
  writeTextToFile("preferences.json", jsonContent);
}

// 从 JSON 文件加载偏好设置
function loadPreferences(onSuccess) {
  readTextFromFile("preferences.json", (content) => {
    try {
      const preferences = JSON.parse(content);
      onSuccess(preferences);
    } catch (e) {
      console.error("解析偏好设置失败：", e);
      onSuccess(null); // 解析失败时返回 null
    }
  });
}
// 使用
const userPrefs = { theme: "light", notifications: true, language: "en" };
savePreferences(userPrefs);
loadPreferences((loadedPrefs) => {
  if (loadedPrefs) {
    console.log("加载的偏好设置：", loadedPrefs);
  } else {
    console.log("使用默认偏好设置");
  }
});
```
### 示例 2：从 URL 下载并保存文件

```javascript
function downloadFile(url, destinationFileName) {
  // 显示加载指示器（可选）
  console.log(`正在下载 ${url}...`);
  fetch(url)
    .then((response) => {
      if (!response.ok) {
        throw new Error(`HTTP 错误！状态码：${response.status}`);
      }
      return response.blob(); // 以 Blob 格式获取文件
    })
    .then((blob) => {
      window.resolveLocalFileSystemURL(
        cordova.file.dataDirectory,
        (rootDir) => {
          rootDir.getFile(
            destinationFileName,
            { create: true, exclusive: false },
            (fileEntry) => {
              fileEntry.createWriter(
                (fileWriter) => {
                  fileWriter.onwriteend = () => {
                    console.log(`文件已下载至：${fileEntry.fullPath}`);
                    // 隐藏加载指示器（可选）
                  };
                  fileWriter.onerror = (error) => {
                    throw new Error(`写入文件失败：${getErrorMessage(error)}`);
                  };
                  fileWriter.write(blob);
                },
                (error) => console.error(`创建写入器失败：${getErrorMessage(error)}`)
              );
            },
            (error) => console.error(`获取文件失败：${getErrorMessage(error)}`)
          );
        },
        (error) => console.error(`解析目录失败：${getErrorMessage(error)}`)
      );
    })
    .catch((error) => {
      console.error(`下载失败：${error.message}`);
      // 隐藏加载指示器（可选）
    });
}

// 使用：下载图片并保存为 "downloaded_image.jpg"
downloadFile("https://example.com/image.jpg", "downloaded_image.jpg");
```

## 平台特定说明

### HarmonyOS

**权限设置**：

* 在鸿蒙系统中，对沙箱文件的读写，无需申请额外权限，默认具备读写权限


## 许可证

本插件基于 **Apache 许可证 2.0 版** 开源。详见 [LICENSE](LICENSE) 文件。

## 参考资料

* Android/iOS 插件：[npmjs.com](https://www.npmjs.com/package/cordova-plugin-file)

* Cordova 团队对 Cordova 生态系统的维护。

* 所有为该插件改进做出贡献的开发者。

* W3C 组织制定的 File API 规范。