文章目录
- [一、MongoDB GridFS简介](#一、MongoDB GridFS简介)
-
- [1. 什么是GridFS](#1. 什么是GridFS)
- [2. GridFS 底层存储结构](#2. GridFS 底层存储结构)
- [3. GridFS 适用场景](#3. GridFS 适用场景)
-
- [3.1 适合使用 GridFS](#3.1 适合使用 GridFS)
- [3.2 不推荐使用 GridFS](#3.2 不推荐使用 GridFS)
- [4. GridFS 核心优势](#4. GridFS 核心优势)
- [5. 基础概念补充](#5. 基础概念补充)
- [二、MongoDB Database Tools安装](#二、MongoDB Database Tools安装)
-
- [1. 下载MongoDB Database Tools安装包](#1. 下载MongoDB Database Tools安装包)
-
- [1.1 下载CentOS7架构安装包](#1.1 下载CentOS7架构安装包)
- [1.2 上传安装包](#1.2 上传安装包)
- [2. 解压MongoDB Database Tools安装包](#2. 解压MongoDB Database Tools安装包)
- [3. 重命名](#3. 重命名)
- [4. 配置环境变量](#4. 配置环境变量)
- [5. bin目录工具介绍](#5. bin目录工具介绍)
- [6. 分发安装程序和环境变量文件](#6. 分发安装程序和环境变量文件)
- 三、使用mongofiles操作GridFS
-
- [1. 基本语法](#1. 基本语法)
-
- [1.1 通用完整语法](#1.1 通用完整语法)
- [1.2 常用连接参数说明](#1.2 常用连接参数说明)
- [1.3 支持的核心操作指令(GridFS增删改查)](#1.3 支持的核心操作指令(GridFS增删改查))
- [2. 文件上传](#2. 文件上传)
-
- [2.1 基本语法](#2.1 基本语法)
- [2.2 操作示例](#2.2 操作示例)
- [2.3 查看files和chunks集合](#2.3 查看files和chunks集合)
- [3. 查看文件](#3. 查看文件)
-
- [3.1 基本语法](#3.1 基本语法)
- [3.2 操作示例](#3.2 操作示例)
- [4. 文件下载](#4. 文件下载)
-
- [4.1 基本语法](#4.1 基本语法)
- [4.2 操作示例](#4.2 操作示例)
- [5. 删除文件](#5. 删除文件)
-
- [5.1 基本语法](#5.1 基本语法)
- [5.2 操作示例](#5.2 操作示例)
- 四、使用Python操作GridFS
-
- [1. 文件上传](#1. 文件上传)
- [2. 查看文件](#2. 查看文件)
- [3. 文件下载](#3. 文件下载)
- [4. 删除文件](#4. 删除文件)
- [5. 完整代码](#5. 完整代码)
一、MongoDB GridFS简介
1. 什么是GridFS
GridFS 是 MongoDB 官方提供的大文件存储规范 ,专门用于解决 MongoDB 单个文档 16MB 大小限制的问题。
MongoDB BSON 文档最大仅支持 16MB,图片、视频、压缩包、日志文件等超大文件无法直接存入普通集合,GridFS 会自动将大文件分块拆分存储,读取时再拼接还原。
2. GridFS 底层存储结构
GridFS 会自动创建两个集合,统一存放在当前数据库下:
- fs.files :文件元数据集合
存储文件整体信息:文件名、文件大小、上传时间、MD5、文件类型、自定义字段、分块数量等,一条记录对应一个完整文件。 - fs.chunks :文件分块数据集合
存储文件二进制分片,默认每块大小255KB;一个文件会拆分成多条 chunk 记录,通过files_id关联对应文件元数据。
存储逻辑流程:
写入文件 → 按255KB切割二进制 → chunks 表存分片 → files 表写入文件整体信息
读取文件 → 根据文件ID查询files → 按分片序号有序读取chunks二进制 → 拼接还原完整文件
3. GridFS 适用场景
3.1 适合使用 GridFS
- 文件大小超过16MB,无法直接存入普通文档;
- 文件数量多、需要统一管理(图片、附件、短视频、备份日志);
- 需要分布式部署MongoDB,文件随数据库一同副本集分片同步;
- 需要按文件ID、文件名快速检索、批量删除文件;
- 无需独立文件服务器,希望数据库统一管理业务数据+附件。
3.2 不推荐使用 GridFS
- 极小文件(几十KB以内):分块存储会产生额外集合开销,直接存在文档更高效;
- 超大高清视频、海量静态资源:专业对象存储(OSS、MinIO)性能、成本更优;
- 需要超高并发文件下载场景:MongoDB IO性能不如专用存储服务。
4. GridFS 核心优势
- 突破16MB单文档限制,支持GB级大文件存储;
- 天然跟随MongoDB副本集/分片,文件自动备份、分布式存储;
- 支持文件元数据自定义扩展,方便业务筛选查询;
- 支持断点续传、分片按需读取(无需加载整个文件);
- 自带文件删除、覆盖、重命名、MD5校验能力。
5. 基础概念补充
- 块大小(chunkSize):默认255KB,上传文件时可自定义;
- _id:文件唯一标识,ObjectId类型;
- md5:文件哈希值,用于校验文件完整性;
- metadata:自定义扩展字段,可存入业务ID、分类、标签等。
二、MongoDB Database Tools安装
1. 下载MongoDB Database Tools安装包
1.1 下载CentOS7架构安装包
官网下载地址:https://www.mongodb.com/try/download/database-tools
CentOS7架构安装包下载地址:https://fastdl.mongodb.org/tools/db/mongodb-database-tools-rhel70-x86_64-100.17.0.tgz
1.2 上传安装包
打开FinalShell工具,切换至hadoop1节点连接窗口,在左侧本地文件列表选中本地桌面下的mongodb-database-tools-rhel70-x86_64-100.17.0.tgz工具压缩包,通过拖拽的方式将该安装包上传至Linux服务器/export/software目录下,等待文件传输完成后,即可在服务器文件列表中看到对应68.8MB的压缩安装包。

2. 解压MongoDB Database Tools安装包
在FinalShell的hadoop1节点命令行窗口执行tar解压命令,将存放在/export/software目录下的mongodb-database-tools压缩包解压至/export/servers目录,执行后控制台会逐行输出解压出的文件目录,其中bin目录包含mongofiles等GridFS操作所需工具,代表解压操作完成。
bash
tar -zxvf /export/software/mongodb-database-tools-rhel70-x86_64-100.17.0.tgz -C /export/servers/

3. 重命名
在hadoop1服务器命令行执行mv重命名指令,将解压后位于/export/servers目录下名称冗长的工具文件夹mongodb-database-tools-rhel70-x86_64-100.17.0简化重命名为mongodb-database-tools,缩短目录路径,方便后续调用mongofiles等GridFS相关工具。
bash
mv /export/servers/mongodb-database-tools-rhel70-x86_64-100.17.0 /export/servers/mongodb-database-tools
4. 配置环境变量
在hadoop1节点终端依次执行多条echo命令,向全局环境变量配置文件/etc/profile中追加MongoDB Tools根目录与PATH路径配置,执行source命令刷新环境变量使其立即生效,最后通过echo打印$MONGODB_TOOLS_HOME校验配置是否成功输出对应安装路径,完成全局环境变量配置,实现任意目录直接调用mongofiles等GridFS工具。
bash
echo >> /etc/profile
echo 'export MONGODB_TOOLS_HOME=/export/servers/mongodb-database-tools' >> /etc/profile
echo 'export PATH=$PATH:$MONGODB_TOOLS_HOME/bin' >> /etc/profile
source /etc/profile
echo $MONGODB_TOOLS_HOME

5. bin目录工具介绍
解压后的mongodb-database-tools工具包bin目录下包含多款MongoDB运维工具,其中mongofiles是操作GridFS的核心命令,各工具作用整理如下:
| 工具名称 | 核心用途 |
|---|---|
| bsondump | BSON文件解析工具,可将BSON格式文件转换为可读JSON文本 |
| mongodump | MongoDB数据库备份工具,导出全库/指定集合数据为BSON备份文件 |
| mongoexport | 集合数据导出工具,支持将集合导出为JSON、CSV格式文件 |
| mongofiles | GridFS专用操作工具,实现文件上传、下载、查询、删除等所有GridFS文件操作 |
| mongoimport | 数据导入工具,将JSON/CSV格式文件批量导入MongoDB集合 |
| mongorestore | 数据库恢复工具,读取mongodump生成的BSON备份文件还原数据 |
| mongostat | 实时数据库状态监控工具,查看连接、读写、锁、内存等运行指标 |
| mongotop | 集合读写耗时监控工具,统计各集合读写操作耗时,定位慢操作集合 |
6. 分发安装程序和环境变量文件
通过scp远程拷贝命令,将hadoop1节点已部署完成的MongoDB Tools工具目录、全局环境变量配置文件,同步分发至集群hadoop2、hadoop3两台节点,实现多节点环境统一。
bash
scp -r /export/servers/mongodb-database-tools root@hadoop2:/export/servers/
scp -r /export/servers/mongodb-database-tools root@hadoop3:/export/servers/
scp /etc/profile root@hadoop2:/etc/
scp /etc/profile root@hadoop3:/etc/
文件分发完成后,需在hadoop2、hadoop3终端执行source命令重载全局配置,让新同步的环境变量立即生效。
bash
source /etc/profile
三、使用mongofiles操作GridFS
1. 基本语法
1.1 通用完整语法
bash
mongofiles [连接参数] <操作指令> [文件/参数]
1.2 常用连接参数说明
连接MongoDB服务的基础参数,所有操作都需要携带:
| 参数 | 作用 |
|---|---|
| --uri | MongoDB 连接串,可一次性携带地址、账号、认证库等全部连接信息,简化命令书写 |
| --host / -h | 指定MongoDB服务地址,单机格式:127.0.0.1:27017 |
| --username / -u | 登录 MongoDB 的数据库用户名,开启权限认证时必须配置 |
| --password / -p | 登录 MongoDB 的数据库用户名,开启权限认证时必须配置 |
| --db / -d | 指定操作的目标数据库,GridFS的fs.files、fs.chunks会生成在该库下 |
| --authenticationDatabase | 指定账号对应的认证数据库,账号创建在 admin 库时需填写admin |
| --port | 指定MongoDB端口,默认27017 |
| --local / -l | 指定本地文件路径,上传 / 下载时用于标识本地文件位置 |
| --replace / -r | 上传文件时覆盖库中已存在同名文件,不添加则重复上传会生成多条文件记录 |
| --prefix | 自定义 GridFS 集合前缀,默认前缀为fs;修改后集合变为自定义前缀.files、自定义前缀.chunks |
1.3 支持的核心操作指令(GridFS增删改查)
| 指令 | 功能说明 | 实操示例 |
|---|---|---|
| put | 上传本地文件到MongoDB GridFS | mongofiles -d gridfs_test put test.zip |
| get | 从GridFS下载文件到本地磁盘 | mongofiles -d gridfs_test get test.zip |
| list | 查询当前库GridFS中存储的所有文件元数据 | mongofiles -d gridfs_test list |
| search | 根据文件名模糊匹配查询文件 | mongofiles -d gridfs_test search zip |
| delete | 根据文件名删除GridFS内指定文件 | mongofiles -d gridfs_test delete test.zip |
| get_regex | 通过正则匹配批量下载符合名称规则的文件 | mongofiles -d gridfs_test get_regex '.*\.png' |
2. 文件上传
2.1 基本语法
bash
mongofiles [连接参数] put 本地文件路径
参数说明:put为上传指令,后跟待上传文件在服务器本地的完整路径,执行后会将文件二进制数据分块存入目标库的fs.chunks,文件元数据写入fs.files集合。
2.2 操作示例
bash
mongofiles --host hadoop2 --port 27020 -d db_test put /export/software/mongodb-linux-x86_64-rhel70-7.0.12.tgz
在hadoop1节点终端执行上述put上传命令,通过--host与--port指定MongoDB服务地址为hadoop2:27020,使用-d指定操作数据库为db_test,将/export/software目录下的MongoDB压缩包上传至GridFS;控制台先输出数据库连接成功日志,随后打印文件分块写入进度,最终提示added gridFile代表文件完整上传成功,此时可进入db_test库查询fs.files、fs.chunks集合验证文件存储信息。

2.3 查看files和chunks集合
通过mongosh客户端连接hadoop2节点27020端口的MongoDB服务。
bash
mongosh --host hadoop2 --port 27020
切换到存放GridFS文件的db_test数据库,执行show collections可看到上传文件后自动生成的fs.files、fs.chunks两个GridFS专属集合;
执行db.fs.files.find({})能够查询到刚才上传压缩包的完整元数据,包含文件唯一ID、文件总大小、单块分片大小、上传时间、存储文件名等信息;
执行db.fs.chunks.find({})则可以查看该文件被拆分后的所有二进制分片记录,每条分片数据通过files_id关联对应文件元数据,直观验证GridFS分块存储的底层逻辑。
bash
use db_test
show collections
db.fs.files.find({})
db.fs.chunks.find({})
exit

fs.files 核心键说明:
| 字段名 | 字段含义 |
|---|---|
| length | 完整文件总字节大小,代表原始文件体积 |
| chunkSize | 单个分块的字节容量,默认255KB(261120字节) |
| uploadDate | 文件上传的时间戳,记录文件存入GridFS的时间 |
| filename | GridFS中存储的文件名称,上传时默认使用本地文件完整路径 |
| _id | 文件唯一ObjectId标识,用于关联fs.chunks中的分片数据 |
| metadata | 自定义扩展元数据字段,可自行存入业务标签、分类等信息 |
fs.chunks 核心键说明:
| 字段名 | 字段含义 |
|---|---|
| files_id | 关联fs.files文档的ObjectId,区分分片归属哪个文件 |
| n | 分片序号,读取文件时按照该数字升序拼接所有二进制块 |
| data | 存储当前分片对应的二进制文件数据 |
3. 查看文件
3.1 基本语法
mongofiles 提供 list 全量查询、search 模糊检索两种查看文件语法:
bash
# 1. 列出数据库内所有GridFS文件
mongofiles [连接参数] list
# 2. 根据关键字模糊匹配文件名查询
mongofiles [连接参数] search 关键词
3.2 操作示例
示例1:列出数据库中全部存储文件
bash
mongofiles --host hadoop2 --port 27020 -d db_test list
指定MongoDB服务地址hadoop2:27020、目标数据库db_test,执行list指令,控制台会打印当前库下所有存入GridFS的文件名称、文件大小等元数据。

示例2:模糊搜索带指定关键词的文件
bash
mongofiles --host hadoop2 --port 27020 -d db_test search tgz
使用search指令搭配关键词tgz,模糊匹配文件名中包含tgz的所有文件,适用于批量筛选压缩包、图片、日志等特定类型文件,快速定位目标资源。

4. 文件下载
4.1 基本语法
基础下载语法:从GridFS拉取文件保存到本地
bash
mongofiles [连接参数] get GridFS内文件名 -l [本地保存路径] [--overwriteLocal]
bash
mongofiles [连接参数] get_regex "正则表达式"
4.2 操作示例
示例1:指定文件名下载文件
若为指定保存目录,文件会下载到当前执行命令的目录;指定保存目录下载时,可重名命文件名;下载GridFS中的文件,并重命名保存到/export/目录下,本地文件名为mongodb.tgz。
bash
mongofiles --host hadoop2 --port 27020 -d db_test get /export/software/mongodb-linux-x86_64-rhel70-7.0.12.tgz -l /export/mongodb.tgz

示例2:正则批量下载(get_regex)
该命令默认会按照文件存入 GridFS 时记录的原始完整路径还原文件,直接下载至上传时对应的目录。
bash
mongofiles --host hadoop2 --port 27020 -d db_test get_regex '.*\.tgz'

5. 删除文件
5.1 基本语法
基础删除语法:根据GridFS内存储的文件名删除文件;
GridFS内存储文件名:上传后存入fs.files集合的filename字段值,长路径必须用引号包裹;
执行删除后,fs.files内的文件元数据、fs.chunks内所有分片数据会同步清除。
bash
mongofiles [连接参数] delete "GridFS内存储文件名"
5.2 操作示例
连接hadoop2节点27020端口的MongoDB,指定操作库db_test,执行delete指令删除GridFS中存储路径为/export/software/mongodb-linux-x86_64-rhel70-7.0.12.tgz的文件;执行完成后,数据库中该文件对应的元数据文档、所有二进制分片数据全部清除,再通过search或list查询将无法检索到该文件。
bash
mongofiles --host hadoop2 --port 27020 -d db_test delete "/export/software/mongodb-linux-x86_64-rhel70-7.0.12.tgz"

四、使用Python操作GridFS
前置依赖安装:
bash
pip install pymongo
1. 文件上传
python
## 文件上传(对应 mongofiles put 上传命令)
def upload_file():
"""
上传本地固定文件至GridFS存储桶
读取本地文件二进制流,流式上传存入MongoDB大文件分片集合
"""
# 本地待上传文件路径
local_file_path = './software/mongodb-linux-x86_64-rhel70-7.0.12.tgz'
# 存入GridFS内自定义短文件名,规避长绝对路径带来的跨目录安全拦截报错
gridfs_filename = "mongodb-linux7.tgz"
# 获取GridFS存储桶操作对象
bucket = get_gridfs_bucket()
# 二进制只读模式打开本地文件,生成文件流
with open(local_file_path, "rb") as file_stream:
# 流式上传文件流到GridFS,返回文件唯一ObjectId
file_id = bucket.upload_from_stream(gridfs_filename, file_stream)
# 打印上传结果与文件唯一标识
print(f"文件上传完成,文件ID: {file_id}")
2. 查看文件
python
## 查看文件(对应 mongofiles list / mongofiles search 查看命令)
def view_file():
"""
查询GridFS内存储文件,包含全量文件遍历、关键词模糊检索两种逻辑
"""
# 获取GridFS存储桶操作对象
bucket = get_gridfs_bucket()
# 遍历所有文件元数据
print("所有文件元数据:")
for file in bucket.find():
print(
f"ID:{file._id},"
f"文件名:{file.filename},"
f"元数据:{file.metadata},"
f"分片大小:{file.chunk_size},"
f"文件总字节长度:{file.length},"
f"上传时间:{str(file.upload_date)}"
)
# 提取所有文件名称,生成文件名列表
file_list = [file.filename for file in bucket.find()]
print("全部文件列表:", file_list)
# 模糊匹配查询:正则匹配文件名包含tgz的文件,对应mongofiles search tgz
tgz_files = bucket.find(filter={"filename": {"$regex": "tgz"}})
print(f"匹配tgz后缀的文件:")
for file in tgz_files:
print(file.filename)
3. 文件下载
python
## 文件下载(对应 mongofiles get -l 下载命令)
def download_file():
"""
根据GridFS内存储文件名,下载文件到本地指定路径
通过文件ID流式读取分片数据,二进制写入本地磁盘
"""
# 文件本地保存路径
local_save_path = "./export/mongodb.tgz"
# 获取GridFS存储桶操作对象
bucket = get_gridfs_bucket()
# 根据存储文件名查询目标文件元数据,获取第一条匹配结果
target_file = bucket.find({"filename": "mongodb-linux7.tgz"}).next()
# 二进制写入模式打开本地输出文件
with open(local_save_path, "wb") as out_stream:
# 根据文件ID读取所有分片,流式写入本地文件流
bucket.download_to_stream(target_file._id, out_stream)
print("文件下载至 ./export/mongodb.tgz 完成")
4. 删除文件
python
## 删除文件(对应 mongofiles delete 删除命令)
def delete_file():
"""
根据文件名删除GridFS中完整文件,同步删除fs.files元数据与fs.chunks所有分片
"""
# 获取GridFS存储桶操作对象
bucket = get_gridfs_bucket()
# 查询目标文件元数据
target_file = bucket.find({"filename": "mongodb-linux7.tgz"}).next()
# 根据文件唯一ID删除全部文件数据
bucket.delete(target_file._id)
print("GridFS文件删除完成")
5. 完整代码
python
# 导入gridfs模块提供GridFSBucket新版文件存储桶API、MongoDB客户端连接工具
import gridfs
from pymongo import MongoClient
# MongoDB连接配置,与mongofiles命令行连接参数保持一致
# 本地MongoDB服务地址
MONGO_URI = "mongodb://127.0.0.1:27017"
# 操作目标数据库名
DB_NAME = "db_test"
def get_gridfs_bucket():
"""
获取GridFS存储桶操作对象
封装MongoDB连接与GridFSBucket初始化逻辑,统一提供文件操作实例
"""
# 创建MongoDB客户端,建立与本地MongoDB服务的连接
client = MongoClient(MONGO_URI)
# 切换至业务操作数据库 db_test
db = client[DB_NAME]
# 初始化新版GridFSBucket存储桶,自动维护fs.files元数据表、fs.chunks分片数据表
bucket = gridfs.GridFSBucket(db)
return bucket
## 文件上传(对应 mongofiles put 上传命令)
def upload_file():
"""
上传本地固定文件至GridFS存储桶
读取本地文件二进制流,流式上传存入MongoDB大文件分片集合
"""
# 本地待上传文件路径
local_file_path = './software/mongodb-linux-x86_64-rhel70-7.0.12.tgz'
# 存入GridFS内自定义短文件名,规避长绝对路径带来的跨目录安全拦截报错
gridfs_filename = "mongodb-linux7.tgz"
# 获取GridFS存储桶操作对象
bucket = get_gridfs_bucket()
# 二进制只读模式打开本地文件,生成文件流
with open(local_file_path, "rb") as file_stream:
# 流式上传文件流到GridFS,返回文件唯一ObjectId
file_id = bucket.upload_from_stream(gridfs_filename, file_stream)
# 打印上传结果与文件唯一标识
print(f"文件上传完成,文件ID: {file_id}")
## 查看文件(对应 mongofiles list / mongofiles search 查看命令)
def view_file():
"""
查询GridFS内存储文件,包含全量文件遍历、关键词模糊检索两种逻辑
"""
# 获取GridFS存储桶操作对象
bucket = get_gridfs_bucket()
# 遍历所有文件元数据
print("所有文件元数据:")
for file in bucket.find():
print(
f"ID:{file._id},"
f"文件名:{file.filename},"
f"元数据:{file.metadata},"
f"分片大小:{file.chunk_size},"
f"文件总字节长度:{file.length},"
f"上传时间:{str(file.upload_date)}"
)
# 提取所有文件名称,生成文件名列表
file_list = [file.filename for file in bucket.find()]
print("全部文件列表:", file_list)
# 模糊匹配查询:正则匹配文件名包含tgz的文件,对应mongofiles search tgz
tgz_files = bucket.find(filter={"filename": {"$regex": "tgz"}})
print(f"匹配tgz后缀的文件:")
for file in tgz_files:
print(file.filename)
## 文件下载(对应 mongofiles get -l 下载命令)
def download_file():
"""
根据GridFS内存储文件名,下载文件到本地指定路径
通过文件ID流式读取分片数据,二进制写入本地磁盘
"""
# 文件本地保存路径
local_save_path = "./export/mongodb.tgz"
# 获取GridFS存储桶操作对象
bucket = get_gridfs_bucket()
# 根据存储文件名查询目标文件元数据,获取第一条匹配结果
target_file = bucket.find({"filename": "mongodb-linux7.tgz"}).next()
# 二进制写入模式打开本地输出文件
with open(local_save_path, "wb") as out_stream:
# 根据文件ID读取所有分片,流式写入本地文件流
bucket.download_to_stream(target_file._id, out_stream)
print("文件下载至 ./export/mongodb.tgz 完成")
## 删除文件(对应 mongofiles delete 删除命令)
def delete_file():
"""
根据文件名删除GridFS中完整文件,同步删除fs.files元数据与fs.chunks所有分片
"""
# 获取GridFS存储桶操作对象
bucket = get_gridfs_bucket()
# 查询目标文件元数据
target_file = bucket.find({"filename": "mongodb-linux7.tgz"}).next()
# 根据文件唯一ID删除全部文件数据
bucket.delete(target_file._id)
print("GridFS文件删除完成")
# 程序测试入口,顺序执行上传、查看、下载、删除完整流程
if __name__ == "__main__":
# 1. 执行文件上传操作
upload_file()
# 2. 查询并打印库内所有文件与匹配tgz的文件
view_file()
# 3. 将GridFS中的文件下载到本地指定目录
download_file()
# 4. 删除GridFS中存储的目标文件
delete_file()
运行结果如下所示:
文件上传完成,文件ID: 6a3294971b9a7b883e1a964d
所有文件元数据:
ID:6a3294971b9a7b883e1a964d,文件名:mongodb-linux7.tgz,元数据:None,分片大小:261120,文件总字节长度:84899620,上传时间:2026-06-17 12:35:35.987000
全部文件列表: ['mongodb-linux7.tgz']
匹配tgz后缀的文件:
mongodb-linux7.tgz
文件下载至 ./export/mongodb.tgz 完成
GridFS文件删除完成