# 将文件上传到 Hub

共享您的文件和工作成果是 Hub 的重要组成部分。`huggingface_hub` 提供了多种将文件上传到 Hub 的选项。您可以独立使用这些函数，也可以将它们集成到您的库中，从而让用户与 Hub 的交互更加便捷。

每当您需要将文件上传到 Hub 时，都需要登录您的 Hugging Face 账户。有关身份验证的更多详细信息，请参阅[此部分](../quick-start#authentication)。

## 上传文件

使用 [create_repo()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.create_repo) 创建仓库后，您可以使用 [upload_file()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.upload_file) 将文件上传到该仓库。

指定要上传的文件路径、在仓库中上传文件的目标位置，以及要添加该文件的仓库名称。根据仓库类型，您可以选择将仓库类型设置为 `dataset`、`model` 或 `space`。

```py
>>> from huggingface_hub import HfApi
>>> api = HfApi()
>>> api.upload_file(
...     path_or_fileobj="/path/to/local/folder/README.md",
...     path_in_repo="README.md",
...     repo_id="username/test-dataset",
...     repo_type="dataset",
... )
```

## 上传文件夹

使用 [upload_folder()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.upload_folder) 函数将本地文件夹上传到现有仓库。指定要上传的本地文件夹路径、在仓库中上传文件夹的目标位置，以及要添加该文件夹的仓库名称。根据仓库类型，您可以选择将仓库类型设置为 `dataset`、`model` 或 `space`。

```py
>>> from huggingface_hub import HfApi
>>> api = HfApi()

# Upload all the content from the local folder to your remote Space.
# By default, files are uploaded at the root of the repo
>>> api.upload_folder(
...     folder_path="/path/to/local/space",
...     repo_id="username/my-cool-space",
...     repo_type="space",
... )
```

默认情况下，`.gitignore` 文件会被用于确定哪些文件应提交。默认情况下，我们会检查提交中是否存在 `.gitignore` 文件；如果不存在，则检查 Hub 上是否存在该文件。请注意，只有位于目录根部的 `.gitignore` 文件才会被使用。我们不会检查子目录中的 `.gitignore` 文件。

如果不想使用硬编码的 `.gitignore` 文件，可以使用 `allow_patterns` 和 `ignore_patterns` 参数来筛选要上传的文件。这些参数接受单个模式或模式列表。模式是标准通配符（globbing 模式），文档见 [此处](https://tldp.org/LDP/GNU-Linux-Tools-Summary/html/x11655.htm)。如果同时提供了 `allow_patterns` 和 `ignore_patterns`，则两个约束条件都会生效。

除了 `.gitignore` 文件和允许/忽略模式外，任何子目录中存在的 `.git/` 文件夹都会被忽略。

```py
>>> api.upload_folder(
...     folder_path="/path/to/local/folder",
...     path_in_repo="my-dataset/train", # Upload to a specific folder
...     repo_id="username/test-dataset",
...     repo_type="dataset",
...     ignore_patterns="**/logs/*.txt", # Ignore all text logs
... )
```

你还可以使用 `delete_patterns` 参数来指定要在同一提交中从仓库删除的文件。如果你想在向远程文件夹推送文件之前清理该文件夹，但又不清楚其中已存在哪些文件，这一功能会非常有用。

以下示例将本地 `./logs` 文件夹上传到远程 `/experiment/logs/` 文件夹。仅上传 txt 文件，但在此之前，会先删除仓库中所有之前的日志。所有这些操作都在一次提交中完成。
```py
>>> api.upload_folder(
...     folder_path="/path/to/local/folder/logs",
...     repo_id="username/trained-model",
...     path_in_repo="experiment/logs/",
...     allow_patterns="*.txt", # Upload all local text files
...     delete_patterns="*.txt", # Delete all remote text files before
... )
```

### 文件如何上传

当 `hf_xet` 已安装（默认情况下即如此）时，[upload_folder()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.upload_folder) 会通过流式管道上传文件：文件会与 Hub 进行比对，上传至 Xet 存储后端（该后端内部会执行分块、去重和传输重试），并以自适应批次进行提交，所有步骤均并行执行。实际上这意味着：

- **任意大小的文件夹**：较小的文件夹会在单次提交中上传，而包含大量文件的文件夹会自动拆分为多个提交，以确保不超过服务器限制。当发生这种情况时，后续提交的提交信息会带有 ` (part 2)`、` (part 3)` 等后缀。
- **可恢复**：如果上传因任何原因中断，只需重新运行相同的调用即可。已提交的文件会被检测并跳过，已上传的数据块会被去重——重新上传它们几乎不会传输任何数据。整个过程不涉及本地状态：您甚至可以从另一台机器恢复上传。一个例外是：当使用 `create_pr=True` 时，重新运行会打开一个新的拉取请求。我们建议在恢复上传时，改为使用 `revision="refs/pr/N"` 重新运行。
- **无重复读取**：文件在分块上传时即进行哈希计算，仅需一次读取。上传开始前没有单独的“哈希”阶段。

实时进度显示会跟踪以下三个阶段：

```
Found 5,000 files to upload
  Preparing   ████████████████████  5,000 / 5,000 ✓
  Uploading   ██████████████░░░░░░  423 / 603 files  3.8GB · 19.7MB/s
  Committing  ██████████████████░░  4,580 / 5,000  6 commits
```

如果未安装 `hf_xet`，[upload_folder()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.upload_folder) 将回退到旧版行为：先对所有内容进行哈希计算，通过 HTTP 上传，然后创建单个提交。我们始终建议保持 `hf_xet` 处于已安装状态，以获得更好的健壮性

## 从 CLI 上传

您可以在终端中使用 `hf upload` 命令将文件直接上传到 Hub。该命令内部使用了上述的 [upload_file()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.upload_file) 和 [upload_folder()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.upload_folder) 辅助函数。

您可以上传单个文件或整个文件夹：

```bash
# Usage:  hf upload [repo_id] [local_path] [path_in_repo]
>>> hf upload Wauplin/my-cool-model ./models/model.safetensors model.safetensors
https://huggingface.co/Wauplin/my-cool-model/blob/main/model.safetensors

>>> hf upload Wauplin/my-cool-model ./models .
https://huggingface.co/Wauplin/my-cool-model/tree/main
```

`local_path` 和 `path_in_repo` 是可选的，可以隐式推断。如果未设置 `local_path`，该工具会检查是否存在与 `repo_id` 同名的本地文件夹或文件。如果是，则上传其内容。否则，将抛出异常，要求用户显式设置 `local_path`。无论如何，如果未设置 `path_in_repo`，文件将上传到仓库的根目录。

目标也可以表示为单个 `hf://` URI，其语法为 `hf://[<TYPE>/]<ID>[@<REVISION>][/<PATH>]`（完整语法请参阅 [HF URIs 参考](../package_reference/hf_uris)）。仓库类型、修订版本和 `path_in_repo` 将从 URI 中读取，因此不能与 `--repo-type` 和 `--revision` 选项同时使用：

```bash
# Upload a single file to a dataset on a specific branch
>>> hf upload hf://datasets/Wauplin/my-cool-dataset@my-branch/data/train.csv ./train.csv
https://huggingface.co/datasets/Wauplin/my-cool-dataset/blob/my-branch/data/train.csv
```

> [!TIP]
> 为了在上传大文件时获得最大吞吐量，请设置 [`HF_XET_HIGH_PERFORMANCE=1`](../package_reference/environment_variables#hf_xet_high_performance) 环境变量。这将启用 `hf_xet` 的高性能模式，从而充分利用可用的带宽和 CPU 核心。注意：由于 `hf_transfer` 已被移除并替换为 `hf_xet`，因此不再使用旧版的 `HF_HUB_ENABLE_HF_TRANSFER=1` 标志——请改为设置 `HF_XET_HIGH_PERFORMANCE=1`。

有关 CLI 上传命令的更多详细信息，请参阅 [CLI 指南](./cli#hf-upload)。

## 上传大文件夹

[upload_folder()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.upload_folder) 和 `hf upload` 命令是将文件上传到 Hub 的常用解决方案，即使是非常大的文件夹也适用。文件会通过多次提交流式传输到 Hub，如果过程中断，流程会自动恢复。只需重新运行相同的调用，已上传的文件会被跳过。

```py
>>> api.upload_folder(
...     repo_id="HuggingFaceM4/Docmatix",
...     repo_type="dataset",
...     folder_path="/path/to/local/docmatix",
... )
```

或从终端：

```sh
hf upload HuggingFaceM4/Docmatix --repo-type=dataset /path/to/local/docmatix
```

### 大型上传的技巧与窍门

在处理仓库中的大量数据时，有一些限制需要注意。考虑到流式传输数据所需的时间，如果在流程末尾上传/推送失败，或者在 hf.co 上或本地操作时遇到体验下降的情况，都会非常令人烦恼。

请参阅我们的[仓库限制与建议](https://huggingface.co/docs/hub/repositories-recommendations)指南，了解如何在 Hub 上组织仓库的最佳实践。接下来，让我们分享一些实用技巧，让您的上传过程尽可能顺畅。

- **从小处着手**：我们建议先用少量数据来测试你的上传脚本。当失败只花费很少时间时，迭代脚本会更容易。
- **预期会出现失败**：流式传输大量数据是一项具有挑战性的任务。你无法预知会发生什么，但最好始终假设至少会有一次失败——无论原因是你的机器、你的网络连接还是我们的服务器。例如，如果你计划上传大量文件，最好在上传下一批文件之前，在本地记录哪些文件已经上传过。可以确保已提交的 LFS 文件永远不会被重复上传，但在客户端进行检查仍然可以节省一些时间。[upload_folder()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.upload_folder) 正是为你完成这项工作的。
- **使用 `hf_xet`**：它利用了 Hub 的新存储后端，使用 Rust 编写，现已向所有人开放。实际上，在使用 `huggingface_hub` 时，`hf_xet` 已默认启用。为了获得最佳性能，请将 [`HF_XET_HIGH_PERFORMANCE=1`](../package_reference/environment_variables#hf_xet_high_performance) 设置为环境变量。请注意，启用高性能模式后，该工具将尝试使用所有可用的带宽和 CPU 核心。

## 高级功能

在大多数情况下，你只需要使用 [upload_file()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.upload_file) 和 [upload_folder()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.upload_folder) 即可将文件上传到 Hub。不过，`huggingface_hub` 还提供了更多高级功能，让操作更加便捷。让我们来看看这些功能！

### 更快的上传

利用 `hf_xet` 实现更快的上传，它是 [`xet-core`](https://github.com/huggingface/xet-core) 库的 Python 绑定，通过基于块的重复数据删除来加速上传和下载。`hf_xet` 可与 `huggingface_hub` 无缝集成，但它使用的是 Rust `xet-core` 库和 Xet 存储，而非 LFS。

`hf_xet` 使用 Xet 存储系统，该系统将文件拆分为不可变的块，并将这些块的集合（称为块或 xorbs）存储在远程，在请求时检索它们以重新组装文件。在上传时，在确认用户有权写入此仓库后，`hf_xet` 会扫描文件，将其拆分为块，并将这些块收集到 xorbs 中（并在已知块之间进行去重），然后会上传这些 xorbs 到 Xet 内容寻址服务（CAS），该服务将验证 xorbs 的完整性，注册 xorb 元数据以及 LFS SHA256 哈希（以支持查找/下载），并将 xorbs 写入远程存储。

要启用此功能，只需安装最新版本的 `huggingface_hub`：

```bash
pip install -U "huggingface_hub"
```

从 `huggingface_hub` 0.32.0 版本开始，此操作还将安装 `hf_xet`。

所有其他 `huggingface_hub` API 将继续正常工作，无需任何修改。要了解 Xet 存储和 `hf_xet` 的优势，请参阅此 [部分](https://huggingface.co/docs/hub/xet/index)。

**集群 / 分布式文件系统上传注意事项**

从集群上传时，待上传的文件通常位于分布式或网络文件系统（如 NFS、EBS、Lustre、Fsx 等）上。Xet 存储会将这些文件分块，并在本地将其写入块（也称为 xorbs），待块写入完成后即进行上传。为了在从分布式文件系统上传时获得更好的性能，请确保将 [`HF_XET_CACHE`](../package_reference/environment_variables#hfxetcache) 设置为位于本地磁盘（例如本地 NVMe 或 SSD 磁盘）上的目录。Xet 缓存的默认位置在 `HF_HOME` 下的（`~/.cache/huggingface/xet`），而该位置通常位于用户主目录中，往往也处于分布式文件系统上。

### 非阻塞上传

在某些情况下，你希望在不阻塞主线程的情况下推送数据。这在继续训练的同时上传日志和工件时尤为有用。为此，你可以在 [upload_file()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.upload_file) 和 [upload_folder()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.upload_folder) 中使用 `run_as_future` 参数。这将返回一个 [`concurrent.futures.Future`](https://docs.python.org/3/library/concurrent.futures.html#future-objects) 对象，你可以用它来检查上传状态。

```py
>>> from huggingface_hub import HfApi
>>> api = HfApi()
>>> future = api.upload_folder( # Upload in the background (non-blocking action)
...     repo_id="username/my-model",
...     folder_path="checkpoints-001",
...     run_as_future=True,
... )
>>> future
Future(...)
>>> future.done()
False
>>> future.result() # Wait for the upload to complete (blocking action)
...
```

> [!TIP]
> 使用 `run_as_future=True` 时，后台任务会被放入队列。这意味着可以确保任务按正确的顺序执行。

尽管后台任务主要用于上传数据/创建提交，但你可以使用 [run_as_future()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.run_as_future) 将任意方法加入队列。例如，你可以用它来创建一个仓库，然后在后台向其中上传数据。上传方法中内置的 `run_as_future` 参数只是它的一个别名。

```py
>>> from huggingface_hub import HfApi
>>> api = HfApi()
>>> api.run_as_future(api.create_repo, "username/my-model", exists_ok=True)
Future(...)
>>> api.upload_file(
...     repo_id="username/my-model",
...     path_in_repo="file.txt",
...     path_or_fileobj=b"file content",
...     run_as_future=True,
... )
Future(...)
```

### 在仓库之间复制文件

使用 [copy_files()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.copy_files) 可在 Hub 上的不同仓库之间复制文件或文件夹，而无需下载或重新上传大型数据。当您需要在不同模型变体之间复制权重、在仓库之间复制数据集文件，或在您的多个仓库之间重新组织文件时，此功能非常有用。其底层机制是通过 [CommitOperationCopy](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.CommitOperationCopy) 操作创建一个提交。

```py
>>> from huggingface_hub import HfApi
>>> api = HfApi()

# Copy a single file between repos
>>> api.copy_files(
...     "hf://username/source-model/weights.safetensors",
...     "hf://username/target-model/weights.safetensors",
... )

# Copy an entire folder
>>> api.copy_files(
...     "hf://datasets/username/source-dataset/data/",
...     "hf://datasets/username/target-dataset/data/",
... )
```

您也可以在同一个仓库内复制：

```py
# Duplicate a file in the same repo
>>> api.copy_files(
...     "hf://username/my-model/config.json",
...     "hf://username/my-model/backup/config.json",
... )
```

> [!TIP]
> 在复制文件夹时，源路径末尾的 `/` 采用 rsync 风格的语义，表示复制该文件夹的*内容*，而不将文件夹本身嵌套其中。如果末尾没有 `/`，则文件夹本身会被嵌套到目标位置。

> [!TIP]
> [copy_files()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.copy_files) 还支持将文件复制到 [Buckets](./buckets)。有关更多详细信息，请参阅 [Buckets 指南](./buckets#copy-files-to-bucket)。

### 计划上传

Hugging Face Hub 让保存和版本化数据变得轻而易举。然而，当需要数千次更新同一个文件时，存在一些限制。例如，您可能希望保存训练过程的日志，或已部署 Space 的用户反馈。在这些情况下，将数据作为数据集上传到 Hub 是合理的，但正确执行起来可能颇具挑战。主要原因是，您不希望为数据的每次更新都创建版本，因为这会使 git 仓库变得无法使用。[CommitScheduler](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.CommitScheduler) 类为这一问题提供了解决方案。

其思路是运行一个后台任务，定期将本地文件夹推送到 Hub。假设你有一个 Gradio Space，它接收一些文本作为输入并生成两个翻译版本，然后用户可以选择他们偏好的翻译。对于每次运行，你希望保存输入、输出以及用户偏好，以便分析结果。这是 [CommitScheduler](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.CommitScheduler) 的一个完美用例：你需要将数据保存到 Hub（可能包含数百万条用户反馈），但你并不_需要_实时保存每个用户的输入。相反，你可以将数据保存在本地的 JSON 文件中，并每 10 分钟上传一次。例如：

```py
>>> import json
>>> import uuid
>>> from pathlib import Path
>>> import gradio as gr
>>> from huggingface_hub import CommitScheduler

# Define the file where to save the data. Use UUID to make sure not to overwrite existing data from a previous run.
>>> feedback_file = Path("user_feedback/") / f"data_{uuid.uuid4()}.json"
>>> feedback_folder = feedback_file.parent

# Schedule regular uploads. Remote repo and local folder are created if they don't already exist.
>>> scheduler = CommitScheduler(
...     repo_id="report-translation-feedback",
...     repo_type="dataset",
...     folder_path=feedback_folder,
...     path_in_repo="data",
...     every=10,
... )

# Define the function that will be called when the user submits its feedback (to be called in Gradio)
>>> def save_feedback(input_text:str, output_1: str, output_2:str, user_choice: int) -> None:
...     """
...     Append input/outputs and user feedback to a JSON Lines file using a thread lock to avoid concurrent writes from different users.
...     """
...     with scheduler.lock:
...         with feedback_file.open("a") as f:
...             f.write(json.dumps({"input": input_text, "output_1": output_1, "output_2": output_2, "user_choice": user_choice}))
...             f.write("\n")

# Start Gradio
>>> with gr.Blocks() as demo:
>>>     ... # define Gradio demo + use `save_feedback`
>>> demo.launch()
```

就是这样！用户的输入/输出和反馈将作为数据集在 Hub 上可用。通过使用唯一的 JSON 文件名，可以确保不会覆盖之前运行产生的数据，也不会覆盖其他 Spaces/副本并发推送到同一仓库的数据。

有关 [CommitScheduler](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.CommitScheduler) 的更多详细信息，以下是您需要了解的内容：
- **仅追加：**假设您只会向该文件夹中添加内容。您只能向现有文件追加数据或创建新文件。删除或覆盖文件可能会导致您的仓库损坏。
- **git history**：调度器将每隔 `every` 分钟提交一次该文件夹。为避免过度污染 git 仓库，建议将最小值设置为 5 分钟。此外，调度器被设计为避免空提交。如果在文件夹中未检测到新内容，则计划中的提交将被丢弃。
- **errors:** 调度器作为后台线程运行。在实例化该类时启动，并持续运行，直到调用 `stop()` 或进程退出。如果上传过程中发生错误（例如：连接问题），该错误会被记录，调度器将在下一次计划提交时重试。
- **scripts:** 在生命周期有限的脚本（例如训练）中，将调度器用作上下文管理器。离开 `with` 块时会触发最后一次上传，等待其完成并停止调度器。
- **线程安全：**在大多数情况下，可以安全地假设您可以写入文件而无需担心锁文件。当调度器正在上传时，即使您向该文件夹写入内容，调度器也不会崩溃或损坏。实际上，对于高负载的应用程序，_可能会发生_并发问题。在这种情况下，我们建议使用 `scheduler.lock` 锁来确保线程安全。该锁仅在调度器扫描文件夹以检测更改时被阻塞，而在上传数据时不会阻塞。您可以放心地认为，这不会影响您 Space 上的用户体验。

#### Space 持久化演示

将 Space 中的数据持久化到 Hub 上的 Dataset 是 [CommitScheduler](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.CommitScheduler) 的主要用例。根据具体用例，您可能希望以不同的方式组织数据。该结构必须能够应对并发用户和重启，这通常意味着需要生成 UUID。除了健壮性之外，您还应以 🤗 Datasets 库可读的格式上传数据，以便后续复用。我们创建了一个 [Space](https://huggingface.co/spaces/Wauplin/space_to_dataset_saver)，演示如何保存多种不同的数据格式（您可能需要根据自身的具体需求对其进行调整）。

#### 自定义上传

[CommitScheduler](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.CommitScheduler) 假设你的数据是仅追加的，并且应以“原样”上传。不过，你可能希望自定义数据上传的方式。你可以通过创建一个继承自 [CommitScheduler](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.CommitScheduler) 的类并重写 `push_to_hub` 方法来实现（你可以按任意方式重写它）。它保证会在后台线程中每隔 `every` 分钟被调用一次。你无需担心并发和错误处理，但必须注意其他方面，例如推送空提交或重复数据。

在下面的（简化）示例中，我们重写了 `push_to_hub`，将所有 PNG 文件打包成一个归档文件，以避免给 Hub 上的仓库带来过大负载：

```py
class ZipScheduler(CommitScheduler):
    def push_to_hub(self):
        # 1. List PNG files
        png_files = list(self.folder_path.glob("*.png"))
        if len(png_files) == 0:
            return None  # return early if nothing to commit

        # 2. Zip png files in a single archive
        with tempfile.TemporaryDirectory() as tmpdir:
            archive_path = Path(tmpdir) / "train.zip"
            with zipfile.ZipFile(archive_path, "w", zipfile.ZIP_DEFLATED) as zip:
                for png_file in png_files:
                    zip.write(filename=png_file, arcname=png_file.name)

            # 3. Upload archive
            self.api.upload_file(..., path_or_fileobj=archive_path)

        # 4. Delete local png files to avoid re-uploading them later
        for png_file in png_files:
            png_file.unlink()
```

重写 `push_to_hub` 时，您可以访问 [CommitScheduler](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.CommitScheduler) 的属性，尤其是：
- [HfApi](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi) 客户端：`api`
- 文件夹参数：`folder_path` 和 `path_in_repo`
- 仓库参数：`repo_id`、`repo_type`、`revision`
- 线程锁：`lock`

> [!TIP]
> 如需查看自定义调度器的更多示例，请访问我们的[演示 Space](https://huggingface.co/spaces/Wauplin/space_to_dataset_saver)，其中包含针对不同使用场景的各种实现。

### create_commit

[upload_file()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.upload_file) 和 [upload_folder()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.upload_folder) 函数是高层 API，通常使用起来非常方便。如果您不需要在更低的层级进行操作，我们建议先尝试这些函数。但是，如果您希望在提交（commit）级别进行操作，可以直接使用 [create_commit()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.create_commit) 函数。

[create_commit()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.create_commit) 支持三种类型的操作：

- [CommitOperationAdd](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.CommitOperationAdd) 用于将文件上传到 Hub。如果该文件已存在，则文件内容会被覆盖。此操作接受两个参数：

  - `path_in_repo`: 要上传文件的目标仓库路径。
  - `path_or_fileobj`：文件系统中的文件路径或类文件对象。这是要上传到 Hub 的文件内容。

- [CommitOperationDelete](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.CommitOperationDelete) 用于从仓库中删除文件或文件夹。此操作接受 `path_in_repo` 作为参数。

- [CommitOperationCopy](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.CommitOperationCopy) 用于在仓库内部或跨仓库复制文件。此操作接受以下参数：

  - `src_path_in_repo`：要复制的文件在仓库中的路径。
  - `path_in_repo`：文件应被复制到的仓库路径。
  - `src_revision`：可选 - 如果您想从其他分支/修订版本复制文件，则指定要复制的文件修订版本。
  - `src_repo_id`：可选 - 要从中复制的源仓库（例如 `"username/source-model"`）。默认为目标仓库。
  - `src_repo_type`：可选 - 源仓库的类型（`"model"`、`"dataset"` 或 `"space"`）。当设置了 `src_repo_id` 时必填。

例如，如果您想在 Hub 仓库中上传两个文件并删除一个文件：

1. 使用适当的 `CommitOperation` 来添加或删除文件，以及删除文件夹：

```py
>>> from huggingface_hub import HfApi, CommitOperationAdd, CommitOperationDelete
>>> api = HfApi()
>>> operations = [
...     CommitOperationAdd(path_in_repo="LICENSE.md", path_or_fileobj="~/repo/LICENSE.md"),
...     CommitOperationAdd(path_in_repo="weights.h5", path_or_fileobj="~/repo/weights-final.h5"),
...     CommitOperationDelete(path_in_repo="old-weights.h5"),
...     CommitOperationDelete(path_in_repo="logs/"),
...     CommitOperationCopy(src_path_in_repo="image.png", path_in_repo="duplicate_image.png"),
... ]
```

2. 将您的操作传递给 [create_commit()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.create_commit)：

```py
>>> api.create_commit(
...     repo_id="lysandre/test-model",
...     operations=operations,
...     commit_message="Upload my model weights and license",
... )
```

除了 [upload_file()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.upload_file) 和 [upload_folder()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.upload_folder) 之外，以下函数在底层也使用了 [create_commit()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.create_commit)：

- [delete_file()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.delete_file) 用于从 Hub 上的仓库中删除单个文件。
- [delete_folder()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.delete_folder) 用于从 Hub 上的仓库中删除整个文件夹。
- [metadata_update()](/docs/huggingface_hub/v2.4.0/zh/package_reference/cards#huggingface_hub.metadata_update) 用于更新仓库的元数据。

如需更详细的信息，请参阅 [HfApi](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi) 参考文档。

### 在提交之前预上传 LFS 文件

在某些情况下，你可能希望在调用 commit 之前将大文件上传到 S3 **之前**。例如，如果你正在提交一个由多个在内存中生成的分片组成的数据集，就需要逐个上传这些分片，以避免内存溢出问题。一种解决方案是将每个分片作为仓库上的单独 commit 进行上传。虽然这种做法完全有效，但它存在一个缺点：可能会生成数十个 commit，从而扰乱 git 历史记录。为了解决这个问题，你可以先将文件逐个上传到 S3，然后在最后创建一个单一的 commit。这可以通过将 [preupload_lfs_files()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.preupload_lfs_files) 与 [create_commit()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.create_commit) 结合使用来实现。

> [!WARNING]
> 这是一种面向高级用户的方法。在绝大多数情况下，直接使用 [upload_file()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.upload_file)、[upload_folder()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.upload_folder) 或 [create_commit()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.create_commit) 来处理文件预上传的底层逻辑是最佳选择。[preupload_lfs_files()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.preupload_lfs_files) 的主要注意事项是，在实际创建提交之前，上传的文件在 Hub 上的仓库中尚不可访问。如果您有任何疑问，欢迎在我们的 Discord 或 GitHub issue 中联系我们。

下面是一个简单的示例，说明如何预上传文件：

```py
>>> from huggingface_hub import CommitOperationAdd, preupload_lfs_files, create_commit, create_repo

>>> repo_id = create_repo("test_preupload").repo_id

>>> operations = [] # List of all `CommitOperationAdd` objects that will be generated
>>> for i in range(5):
...     content = ... # generate binary content
...     addition = CommitOperationAdd(path_in_repo=f"shard_{i}_of_5.bin", path_or_fileobj=content)
...     preupload_lfs_files(repo_id, additions=[addition])
...     operations.append(addition)

>>> # Create commit
>>> create_commit(repo_id, operations=operations, commit_message="Commit all shards")
```

首先，我们逐个创建 [CommitOperationAdd](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.CommitOperationAdd) 对象。在实际场景中，这些对象将包含生成的分片。每个文件在生成下一个文件之前都会先上传。在 [preupload_lfs_files()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.preupload_lfs_files) 步骤中，**`CommitOperationAdd` 对象会被修改**。您应仅将其用于直接传递给 [create_commit()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.create_commit)。该对象的主要更新是其中 **移除了二进制内容**，这意味着如果您没有保留对它的另一个引用，它将被垃圾回收。这是预期行为，因为我们不希望将已上传的内容保留在内存中。最后，我们将所有操作传递给 [create_commit()](/docs/huggingface_hub/v2.4.0/zh/package_reference/hf_api#huggingface_hub.HfApi.create_commit) 来创建提交。您可以传入尚未处理的其他操作（添加、删除或复制），它们将被正确处理。

