# 卷、文件夹与文件

卷是数据库下用于组织文件的资源。完成本页操作后，你将创建一个卷，上传文件内容，将文件挂载到卷，并读取文件详情。

## 前提条件

- 已准备 Product API Base URL、个人访问令牌和工作区 ID。
- 已从数据目录（Catalog）API 取得目标数据库的数值 ID。
- 当前身份具有在目标数据库创建卷和文件的权限。

```bash
export PRODUCT_API_BASE_URL='<Product API Base URL ending in /newmoi>'
export PRODUCT_API_KEY='<your-personal-access-token>'
export WORKSPACE_ID='<workspace-id>'
export DATABASE_ID='<database-id>'
```

## 创建卷

```bash
curl -X POST "$PRODUCT_API_BASE_URL/catalog/volume/create" \
  -H "X-API-Key: $PRODUCT_API_KEY" \
  -H "X-Workspace-ID: $WORKSPACE_ID" \
  -H "Content-Type: application/json" \
  -d "{
    \"database_id\": $DATABASE_ID,
    \"name\": \"<VOLUME_NAME>\",
    \"description\": \"<DESCRIPTION>\"
  }"
```

成功响应中的 `data.id` 是数值类型的卷 ID。保存该值：

```json
{
  "code": "OK",
  "msg": "OK",
  "data": {
    "id": 301
  }
}
```

## 上传并挂载文件

文件进入指定卷需要两个动作：

1. 上传文件内容，取得字符串类型的 `file_id`。
2. 使用 `file_id` 和数值类型的 `volume_id` 创建数据目录文件引用。

先发送 multipart 上传请求。上传字段名为 `file`：

```bash
export VOLUME_ID='<volume-id>'

curl -X POST "$PRODUCT_API_BASE_URL/catalog/file/upload" \
  -H "X-API-Key: $PRODUCT_API_KEY" \
  -H "X-Workspace-ID: $WORKSPACE_ID" \
  -F "file=@<LOCAL_FILE_PATH>"
```

成功响应返回文件标识、原始名称和大小：

```json
{
  "code": "OK",
  "msg": "OK",
  "data": {
    "file_id": "<FILE_ID>",
    "original_name": "orders.csv",
    "size": 128,
    "md5": "<MD5>"
  }
}
```

保存 `data.file_id`，然后挂载到卷：

```bash
export FILE_ID='<file-id-from-upload>'

curl -X POST "$PRODUCT_API_BASE_URL/catalog/file/create" \
  -H "X-API-Key: $PRODUCT_API_KEY" \
  -H "X-Workspace-ID: $WORKSPACE_ID" \
  -H "Content-Type: application/json" \
  -d "{
    \"volume_id\": $VOLUME_ID,
    \"file_ids\": [\"$FILE_ID\"]
  }"
```

`file/create` 成功表示文件引用已写入目标卷。上传成功但挂载失败时，应保留 `file_id` 排查，不要反复上传相同内容。

## 读取文件

使用 `file_id` 读取详情：

```bash
curl -X POST "$PRODUCT_API_BASE_URL/catalog/file/info" \
  -H "X-API-Key: $PRODUCT_API_KEY" \
  -H "X-Workspace-ID: $WORKSPACE_ID" \
  -H "Content-Type: application/json" \
  -d "{\"file_id\": \"$FILE_ID\"}"
```

```json
{
  "code": "OK",
  "msg": "OK",
  "data": {
    "file_id": "<FILE_ID>",
    "file_name": "orders.csv",
    "size": 128
  }
}
```

列出卷中的文件使用 `POST /catalog/file/list`，并在筛选条件中传入 `volume_id`。下载和预览分别使用 `/catalog/file/download` 和 `/catalog/file/preview_stream`；它们返回文件流，不是标准 JSON 结果，客户端应关闭响应体并限制写入位置。

## 管理文件夹

| 方法与路径 | 用途 | 关键输入 |
| --- | --- | --- |
| `POST /catalog/folder/create` | 在卷下创建文件夹 | 父卷 ID、数据库 ID、名称 |
| `POST /catalog/folder/update` | 更新文件夹 | 文件夹数值 ID和名称等更新字段 |
| `POST /catalog/folder/clean` | 清空文件夹内容 | 文件夹数值 ID |
| `POST /catalog/folder/delete` | 删除文件夹 | 文件夹数值 ID |

清空和删除是不同操作。`clean` 保留文件夹本身；`delete` 删除文件夹资源。执行前先列出内容和引用，不要根据文件夹名称推断目标 ID。

## 删除文件

`POST /catalog/file/delete_ref` 用于从卷移除文件引用，请求体包含数值 `volume_id` 和字符串数组 `file_ids`。`POST /catalog/file/delete` 删除文件时，同时提供字符串 `id` 和 `volume_id`。

删除前检查该文件是否作为语义模型来源、工作流输入或数据资产使用。删除文件引用不会自动回滚已经产生的工作流产物或导出结果。

## 常见问题

| 现象 | 先检查 | 下一步 |
| --- | --- | --- |
| 上传成功但详情不存在 | 是否已经调用 `/catalog/file/create` | 使用上传返回的 `file_id` 挂载到目标卷。 |
| 挂载失败 | `volume_id` 是否为数值、`file_ids` 是否为字符串数组 | 从数据库子对象重新取得卷 ID 后重试挂载。 |
| 预览或下载失败 | 文件 ID、卷 ID 和当前身份权限 | 先调用文件详情确认对象仍存在，再请求流接口。 |
| 删除被拒绝 | 文件引用和下游任务 | 解除引用后再删除，不重复提交相同删除请求。 |

## 下一步

- [配置用于外部数据源的连接器](connectors.md)
- [运行导入或导出任务](import-export-tasks.md)
- [把文件加入语义模型](../semantic-models/sources-processing.md)
