---
title: "openFile"
description: "打开系统文件选择器，并返回可继续访问的虚拟文件句柄。"
---


> 打开系统文件选择器，并返回可继续访问的虚拟文件句柄。

## 签名

```ts
KSM.dialog.openFile(args?: {
  filters?: string[];
}): Promise<{ file: string | null }>
```

## 平台与权限

| Windows | Android |权限 |
| --- | --- | --- |
|支持 |支持 | `dialog` |

## 参数

|参数 |类型 |必填 |说明 |
| --- | --- | --- | --- |
| `filters` | `string[]` |否 |目标平台的文件过滤值 |

## 返回值

|字段 |类型 |说明 |
| --- | --- | --- |
| `file` | `string \| null` |成功时是 `app://picked/<id>`，取消时为 `null` |

## 行为

- Windows 把每个过滤器同时作为显示名和通配表达式传给 `GetOpenFileNameW`。
- Android 把数组原样放入 `Intent.EXTRA_MIME_TYPES`，例如 `image/png`。
- Windows 只登记已存在的文件。
- Android 通过 `ACTION_OPEN_DOCUMENT` 选择可打开的文件。
- 用户取消或选择失败时返回 `{ file: null }`。
- Android 宿主内部等待 60 秒仍未完成时返回 `{ file: null }`；前端总线默认 10 秒
 先以 `TIMEOUT`拒绝。
- 返回的句柄是能力凭据，不应持久化成可跨会话继续使用的路径。

## 示例

```ts
const picked = await KSM.dialog.openFile({
  filters: ['application/json']
});

if (!picked.file) {
  return;
}

const result = await KSM.fs.readText({ path: picked.file });
```

## 错误

|错误 |场景 |
| --- | --- |
|普通 `TypeError` | `filters` 不是字符串数组 |
| `PERMISSION_DENIED` | `dialog` 权限不可用 |
| `NOT_SUPPORTED` |宿主没有配置文件选择服务 |
| `TIMEOUT` |请求超过桥接层 10 秒超时 |

## 相关

- [saveFile](/docs/kasumi/api/dialog/save-file)
- [fs.readText](/docs/kasumi/api/fs/read-text)