💾 文件存储
ThinkAdmin 提供统一的文件存储引擎,支持多种存储方案,满足不同场景下的数据存储需求。
📚 基础概念
🤔 基本介绍
文件存储是指将用户上传的文件(图片、文档、视频等)保存到服务器或云存储服务的过程。
简单理解:就像把文件放到仓库里,需要的时候再取出来。
实际例子:
用户上传图片 → 保存到云存储 → 返回访问链接
↓
https://example.com/image/abc123.jpgThinkAdmin 提供了统一的存储接口,支持多种存储方案,让开发者可以用相同的代码操作不同的存储服务。
🤔 使用优势
问题1:不同存储方案 API 不同
不使用统一接口时,需要为每种存储方案写不同的代码:
// ❌ 不统一:需要为每种存储写不同的代码
if ($storageType === 'qiniu') {
// 七牛云 API
$qiniu->upload($file);
} elseif ($storageType === 'alioss') {
// 阿里云 OSS API
$oss->putObject($file);
} elseif ($storageType === 'local') {
// 本地存储
move_uploaded_file($file, $path);
}使用统一接口后,代码变得简单:
// ✅ 统一接口:所有存储方案使用相同的代码
Storage::instance()->set($filename, $content);
// 切换存储方案时,只需修改配置,无需修改代码问题2:切换存储方案困难
使用统一接口后,切换存储方案只需修改配置:
// 配置文件中修改存储类型
// config/storage.php
return [
'type' => 'qiniu', // 改为 'alioss' 或 'local' 即可
];📊 存储方案对比
ThinkAdmin 支持多种存储方案,各有特点:
| 存储方式 | 不占服务器空间 | 上传大文件 | 支持CDN加速 | 是否推荐 |
|---|---|---|---|---|
| 本地服务器存储 | ❌ | ❌ | ❌ | ❌ |
| 自建 Alist 存储 | ✔️ | 可配 | ❌ | ✔️ |
| 七牛云空间存储 | ✔️ | ✔️ | ✔️ | ✔️ |
| 又拍云USS存储 | ✔️ | ✔️ | ✔️ | ✔️ |
| 阿里云OSS存储 | ✔️ | ✔️ | ✔️ | ✔️ |
| 腾讯云COS存储 | ✔️ | ✔️ | ✔️ | ✔️ |
本地存储:
- 文件保存在服务器本地
- 简单但占用服务器空间
- 适合小项目或测试环境
云存储:
- 文件保存在云端
- 不占服务器空间,支持 CDN 加速
- 适合生产环境
混合存储:
- 可以根据文件类型选择不同的存储方案
- 例如:图片用云存储,文档用本地存储
⚡ 文件秒传
文件秒传是指当文件已经上传过时,再次上传相同文件时立即成功,无需重新上传。
工作原理:
ThinkAdmin 使用文件 hash(MD5)来判断文件是否已存在:
// 1. 计算文件 hash
$hash = md5_file($filePath);
// 例如:abc123def456...
// 2. 检查文件是否已存在
if (Storage::instance()->has($hash)) {
// 文件已存在,直接返回 URL(秒传)
return Storage::instance()->url($hash);
} else {
// 文件不存在,正常上传
return Storage::instance()->set($hash, $content);
}实际效果:
第一次上传:上传文件 → 保存到云存储 → 返回 URL(需要时间)
第二次上传:检查 hash → 文件已存在 → 立即返回 URL(秒传)📖 相关概念
Hash(哈希)
- 文件的唯一标识
- 相同内容的文件 hash 相同
- 例如:
abc123def456...
CDN(内容分发网络)
- 加速文件访问的网络服务
- 将文件缓存到多个节点,提升访问速度
URL(统一资源定位符)
- 文件的访问地址
- 例如:
https://example.com/image/abc123.jpg
安全目录
- 不允许直接 URL 访问的目录
- 用于存储私密文件
- 只支持本地存储
🚀 主要功能
- 多存储支持: 支持本地存储、云存储等多种方案
- 统一接口: 提供统一的存储接口,简化开发
- 灵活配置: 支持后台动态配置存储参数
- 文件管理: 完整的文件管理功能
- 性能优化: 支持文件秒传和 CDN 加速
- 安全可靠: 提供安全的文件存储解决方案
📋 存储方案对比
| 存储方式 | 不占服务器空间 | 上传大文件 | 支持CDN加速 | 是否推荐 |
|---|---|---|---|---|
| 本地服务器存储 | ❌ | ❌ | ❌ | ❌ |
| 自建 Alist 存储 | ✔️ | 可配 | ❌ | ✔️ |
| 七牛云空间存储 | ✔️ | ✔️ | ✔️ | ✔️ |
| 又拍云USS存储 | ✔️ | ✔️ | ✔️ | ✔️ |
| 阿里云OSS存储 | ✔️ | ✔️ | ✔️ | ✔️ |
| 腾讯云COS存储 | ✔️ | ✔️ | ✔️ | ✔️ |
🌟 推荐方案
七牛云存储: 配置简单性价比高,首次注册认证赠送 10GB 的免费存储空间。立即注册
⚙️ 存储特性
文件命名策略
- Hash 命名: 默认使用文件 hash 命名,同一文件只存储一份
- 日期命名: 支持日期+随机的方式命名(不支持秒传)
- 秒传支持: 相同文件再次上传时立即成功
- URL 访问: 上传后返回可访问的 URL 链接
配置管理
- 后台配置: 通过系统管理界面配置存储参数
- 参数说明: 提供详细的参数说明和配置指导
- 灵活切换: 支持不同存储方案的灵活切换
性能优化
- 文件秒传: 基于文件 hash 实现秒传功能
- CDN 加速: 支持 CDN 加速提升访问速度
- 缓存机制: 内置缓存机制提升性能
- 压缩优化: 支持文件压缩和优化
安全特性
- 访问控制: 支持文件访问权限控制
- 防盗链: 支持防盗链保护
- 加密存储: 支持文件加密存储
- 备份恢复: 支持文件备份和恢复
| 存储方式 | 不占服务器空间 | 上传大文件 | 支持CDN加速 | 是否推荐 |
|---|---|---|---|---|
| 本地服务器存储 | ❌️ | ❌ | ❌ | ❌ |
| 自建 Alist 存储 | ✔️ | 可配 | ❌ | ✔️ |
| 七牛云空间存储 | ✔️ | ✔️ | ✔️ | ✔️ |
| 又拍云USS存储 | ✔️ | ✔️ | ✔️ | ✔️ |
| 阿里云OSS存储 | ✔️ | ✔️ | ✔️ | ✔️ |
| 腾讯云COS存储 | ✔️ | ✔️ | ✔️ | ✔️ |
这里推荐使用 七牛云存储,主要是配置简单性价比高,首次注册认证赠送 10GB 的免费存储空间。 立即注册
- ThinkAdmin 文件存储默认使用文件 hash 命名,同一个文件只会存储一份;
- 支持文件秒传,当文件已经上传到服务之后,再次上传同一个文件时将立即成功;
- 新版本的 ThinkAdmin 支持以日期+随机的方式命名,注意此方法不支持秒传功能;
- 所有文件上传之后,将统一返回 url 可访问的链接地址,直接存储到内容即可访问;
- 更多文件规则可以在系统后台文件管理处配置参数,不同的存储方式配置不同的参数;

⚙️ 自动存储
ThinkAdmin 提供了统一的存储接口,默认自动选择配置的存储引擎,无需手动指定。
📝 基本用法
获取存储实例:
use think\admin\Storage;
// 获取存储实例(自动选择配置的存储引擎)
$storage = Storage::instance();文件操作:
use think\admin\Storage;
$content = '文件内容(原文件内容,文档或二进制文件)';
$filename = '文件名称(支持路径,相对 upload 目录或云存储根目录)';
// 上传文件
$result = Storage::instance()->set($filename, $content);
// 返回:['url' => 'https://...', 'key' => '...', 'hash' => '...']
// 读取文件
$content = Storage::instance()->get($filename);
// 返回:文件内容(字符串)
// 删除文件
$result = Storage::instance()->del($filename);
// 返回:true 或 false
// 判断文件是否存在
$exists = Storage::instance()->has($filename);
// 返回:true 或 false
// 生成文件访问 URL
$url = Storage::instance()->url($filename);
// 返回:https://example.com/image/abc123.jpg
// 获取文件信息
$info = Storage::instance()->info($filename);
// 返回:['url' => '...', 'key' => '...', 'hash' => '...', 'file' => '...']
// 计算文件路径
$path = Storage::instance()->path($filename);
// 返回:文件路径(本地存储)或 URL(云存储)
// 获取上传入口(用于前端直传)
$uploadUrl = Storage::instance()->upload();
// 返回:上传接口地址
// 获取存储区域列表(云存储)
$regions = Storage::instance()->region();
// 返回:['华东' => 'z0', '华北' => 'z1', ...]🔒 安全目录存储
参数 safe 说明:
safe 参数用于存储文件到安全目录(只支持本地存储),不允许直接使用 URL 访问,主要用于上传一些私密文件。
use think\admin\Storage;
// 存储到安全目录(safe = true)
$result = Storage::instance()->set(
'private/document.pdf',
$fileContent,
true // safe 参数为 true
);
// 文件保存在安全目录,无法通过 URL 直接访问
// 读取安全目录文件
$content = Storage::instance()->get('private/document.pdf', true);
// 安全目录文件需要特殊处理才能访问
// 例如:通过控制器方法验证权限后返回文件内容使用场景:
- 私密文档存储
- 需要权限验证的文件
- 不允许直接访问的文件
注意事项:
- 安全目录只支持本地存储
- 云存储不支持安全目录功能
🎯 指定存储
// 本地服务器文件操作
use think\admin\storage\LocalStorage;
$content = '文件内容 ( 原文件内容,文档或二进制文件 )';
$filename = '文件名称 ( 支持路径,相对 upload 目录 或 云存储根目录 ) ';
$result = LocalStorage::instance()->upload(); // 上传入口
$result = LocalStorage::instance()->set($filename, $content, $safe); // 上传文件
$result = LocalStorage::instance()->get($filename, $safe); // 读取文件
$result = LocalStorage::instance()->del($filename, $safe); // 删除文件
$result = LocalStorage::instance()->has($filename, $safe); // 判断是否存在
$result = LocalStorage::instance()->url($filename, $safe); // 生成文件链接
$result = LocalStorage::instance()->info($filename, $safe); // 获取文件参数// 自建 Alist 存储
// 该方式是自行搭建的存储,灵活私有,可使用内网存储
use think\admin\storage\AlistStorage;
$content = '文件内容 ( 原文件内容,文档或二进制文件 )';
$filename = '文件名称 ( 支持路径,相对 upload 目录 或 云存储根目录 ) ';
$result = AlistStorage::instance()->upload(); // 上传入口
$result = AlistStorage::instance()->region(); // 存储区域
$result = AlistStorage::instance()->set($filename, $content); // 上传文件
$result = AlistStorage::instance()->get($filename); // 读取文件
$result = AlistStorage::instance()->del($filename); // 删除文件
$result = AlistStorage::instance()->has($filename); // 判断是否存在
$result = AlistStorage::instance()->url($filename); // 生成文件链接
$result = AlistStorage::instance()->info($filename); // 获取文件参数// 阿里云 OSS 存储
use think\admin\storage\AliossStorage;
$content = '文件内容 ( 原文件内容,文档或二进制文件 )';
$filename = '文件名称 ( 支持路径,相对 upload 目录 或 云存储根目录 ) ';
$location = '文件远程链接,如:https://v6.thinkadmin.top/favicon.ico';
$result = AliossStorage::instance()->upload(); // 上传入口
$result = AliossStorage::instance()->region(); // 存储区域
$result = AliossStorage::instance()->set($filename, $content); // 上传文件
$result = AliossStorage::instance()->get($filename); // 读取文件
$result = AliossStorage::instance()->del($filename); // 删除文件
$result = AliossStorage::instance()->has($filename); // 判断是否存在
$result = AliossStorage::instance()->url($filename); // 生成文件链接
$result = AliossStorage::instance()->info($filename); // 获取文件参数// 腾讯云 COS 存储
use think\admin\storage\TxcosStorage;
$content = '文件内容 ( 原文件内容,文档或二进制文件 )';
$filename = '文件名称 ( 支持路径,相对 upload 目录 或 云存储根目录 ) ';
$result = TxcosStorage::instance()->upload(); // 上传入口
$result = TxcosStorage::instance()->region(); // 存储区域
$result = TxcosStorage::instance()->set($filename, $content); // 上传文件
$result = TxcosStorage::instance()->get($filename); // 读取文件
$result = TxcosStorage::instance()->del($filename); // 删除文件
$result = TxcosStorage::instance()->has($filename); // 判断是否存在
$result = TxcosStorage::instance()->url($filename); // 生成文件链接
$result = TxcosStorage::instance()->info($filename); // 获取文件参数// 七牛云存储
use think\admin\storage\QiniuStorage;
$content = '文件内容 ( 原文件内容,文档或二进制文件 )';
$filename = '文件名称 ( 支持路径,相对 upload 目录 或 云存储根目录 ) ';
$result = QiniuStorage::instance()->upload(); // 上传入口
$result = QiniuStorage::instance()->region(); // 存储区域
$result = QiniuStorage::instance()->set($filename, $content); // 上传文件
$result = QiniuStorage::instance()->get($filename); // 读取文件
$result = QiniuStorage::instance()->del($filename); // 删除文件
$result = QiniuStorage::instance()->has($filename); // 判断是否存在
$result = QiniuStorage::instance()->url($filename); // 生成文件链接
$result = QiniuStorage::instance()->info($filename); // 获取文件参数📦 静态方法
Storage 类还提供了一些静态方法,可以直接调用,无需实例化:
use think\admin\Storage;
// 获取文件相对名称(基于 hash 或指定函数)
$filename = Storage::name($url, $ext = '', $pre = '', $fun = 'md5');
// 示例:Storage::name('https://example.com/image.jpg', 'jpg', 'image')
// 返回:image/ab/cd1234567890abcdef1234567890ab.jpg
// 下载文件到本地
$result = Storage::down($url, $force = false, $expire = 0);
// $force: 是否强制重新下载
// $expire: 文件保留时间(秒),0 表示永久保留
// 获取文件 MIME 类型
$mime = Storage::mime($exts, $mime = []);
// 示例:Storage::mime('jpg,png') 返回 'image/jpeg,image/png'
// 获取所有 MIME 类型映射
$mimes = Storage::mimes();
// 获取支持的存储类型列表
$types = Storage::types();
// 返回:['local' => '本地服务器存储', 'qiniu' => '七牛云对象存储', ...]
// 使用 CURL 读取网络资源
$content = Storage::curlGet($url);
// 保存 base64 图片数据
$result = Storage::saveImage($base64, $prefix = 'image', $safemode = false);
// 示例:Storage::saveImage('data:image/png;base64,iVBORw0KG...', 'avatar')实际应用案例
<?php
declare(strict_types=1);
namespace app\admin\controller;
use think\admin\Controller;
use think\admin\Storage;
/**
* 文件管理示例
* @class File
* @package app\admin\controller
*/
class File extends Controller
{
/**
* 下载远程文件并保存
* @auth true
*/
public function download()
{
$url = input('url');
if (empty($url)) {
$this->error('文件地址不能为空');
}
// 下载文件到本地(带缓存,24小时内不重复下载)
$result = Storage::down($url, false, 86400);
$this->success('文件下载成功', $result);
}
/**
* 保存 base64 图片
* @auth true
*/
public function saveImage()
{
$base64 = input('image');
if (empty($base64)) {
$this->error('图片数据不能为空');
}
// 保存 base64 图片到云存储
$result = Storage::saveImage($base64, 'avatar');
$this->success('图片保存成功', $result);
}
/**
* 处理富文本编辑器中的 base64 图片
* @auth true
*/
public function processContent()
{
$content = input('content');
// 抓取内容中的 base64 图片并上传到云端
$content = preg_replace_callback(
'/"data:image\/([a-zA-Z]+);base64,(.*)"/',
function ($matches) {
// 保存 base64 图片到云存储
$result = Storage::saveImage(trim($matches[0], '"'));
return '"' . $result['url'] . '"';
},
$content
);
// 保存处理后的内容
// ...
$this->success('内容处理成功');
}
}🚀 高级用法
📋 文件操作流程
完整的文件操作流程包括:检查、上传、读取、获取信息、生成 URL、删除。
use think\admin\Storage;
// 获取存储实例
$storage = Storage::instance();
// 1. 检查文件是否存在
if ($storage->has('image/ab/cd123456.jpg')) {
// 文件存在,可以执行后续操作
echo '文件已存在';
}
// 2. 上传文件
$result = $storage->set('image/ab/cd123456.jpg', file_get_contents($filePath));
// 返回:['url' => 'https://...', 'key' => 'image/ab/cd123456.jpg', 'hash' => '...']
// 3. 读取文件内容
$content = $storage->get('image/ab/cd123456.jpg');
// 返回:文件内容(字符串)
// 4. 获取文件信息
$info = $storage->info('image/ab/cd123456.jpg');
// 返回:['url' => '...', 'key' => '...', 'hash' => '...', 'file' => '...']
// 5. 生成文件访问 URL
$url = $storage->url('image/ab/cd123456.jpg');
// 返回:https://example.com/image/ab/cd123456.jpg
// 6. 删除文件
$storage->del('image/ab/cd123456.jpg');
// 返回:true 或 false📝 文件命名策略
ThinkAdmin 支持多种文件命名策略,推荐使用 hash 命名(支持秒传)。
Hash 命名(推荐):
// 使用 hash 命名(推荐,支持秒传)
$filename = Storage::name($filePath, 'jpg', 'image');
// 返回:image/ab/cd1234567890abcdef1234567890ab.jpg
// 工作原理:
// 1. 计算文件 MD5:abc123def456...
// 2. 取前 2 位作为目录:ab
// 3. 取 3-4 位作为子目录:cd
// 4. 完整 hash 作为文件名:abc123def456...
// 5. 最终路径:image/ab/cd/abc123def456....jpg日期命名:
// 使用日期+随机命名(不支持秒传)
$filename = Storage::name($filePath, 'jpg', 'image', 'date');
// 返回:image/2024/01/15/abc123def456.jpg
// 格式:{prefix}/{年}/{月}/{日}/{随机字符串}.{扩展名}自定义命名:
// 自定义命名函数
$filename = Storage::name($filePath, 'jpg', 'image', function($path, $ext) {
// $path: 文件路径
// $ext: 文件扩展名
return 'custom/' . md5($path) . '.' . $ext;
});
// 返回:custom/abc123def456.jpg📦 批量文件操作
批量操作可以提高效率,适用于需要处理多个文件的场景。
批量上传:
// 批量上传文件
$files = [
['path' => 'image1.jpg', 'content' => $content1],
['path' => 'image2.jpg', 'content' => $content2],
['path' => 'image3.jpg', 'content' => $content3],
];
$results = [];
foreach ($files as $file) {
// 生成文件名
$filename = Storage::name($file['path'], 'jpg', 'image');
// 上传文件
$result = Storage::instance()->set($filename, $file['content']);
$results[] = $result;
}
// $results 包含所有上传结果批量删除:
// 批量删除文件
$keys = [
'image/ab/cd1.jpg',
'image/ab/cd2.jpg',
'image/ab/cd3.jpg',
];
foreach ($keys as $key) {
Storage::instance()->del($key);
}🔍 文件类型验证
文件类型验证可以防止上传不安全的文件类型。
获取 MIME 类型:
// 获取文件 MIME 类型
$mime = Storage::mime('jpg,png');
// 返回:image/jpeg,image/png
// 获取所有 MIME 类型映射
$mimes = Storage::mimes();
// 返回:['jpg' => 'image/jpeg', 'png' => 'image/png', ...]验证文件扩展名:
// 验证文件扩展名
$allowedExts = ['jpg', 'png', 'gif'];
$fileExt = pathinfo($filename, PATHINFO_EXTENSION);
if (!in_array(strtolower($fileExt), $allowedExts)) {
$this->error('不支持的文件类型!');
}完整验证示例:
<?php
// 文件上传验证
$file = $this->request->file('file');
// 1. 验证文件是否存在
if (empty($file)) {
$this->error('请选择要上传的文件');
}
// 2. 验证文件类型
$allowExts = ['jpg', 'png', 'gif'];
$ext = strtolower($file->extension());
if (!in_array($ext, $allowExts)) {
$this->error('不支持的文件类型!');
}
// 3. 验证文件大小
$maxSize = 2097152; // 2MB
if ($file->getSize() > $maxSize) {
$this->error('文件大小超过限制!');
}
// 4. 验证 MIME 类型
$mime = Storage::mime($ext);
$fileMime = $file->getMime();
if (strpos($mime, $fileMime) === false) {
$this->error('文件类型不匹配!');
}🌍 云存储区域配置
不同云存储支持不同的区域,选择合适的区域可以提升访问速度。
获取区域列表:
// 获取存储区域列表(不同云存储支持的区域)
use think\admin\storage\QiniuStorage;
use think\admin\storage\AliossStorage;
use think\admin\storage\TxcosStorage;
// 七牛云区域
$qiniuRegions = QiniuStorage::region();
// 返回:['华东' => 'z0', '华北' => 'z1', '华南' => 'z2', ...]
// 阿里云 OSS 区域
$aliossRegions = AliossStorage::region();
// 返回:['华东1(杭州)' => 'oss-cn-hangzhou', ...]
// 腾讯云 COS 区域
$txcosRegions = TxcosStorage::region();
// 返回:['华东地区(上海)' => 'ap-shanghai', ...]选择区域:
// 在后台配置中选择区域
// 系统管理 → 文件管理 → 存储配置 → 选择区域
// 区域选择建议:
// 1. 选择距离用户最近的区域
// 2. 选择距离服务器最近的区域
// 3. 考虑成本因素❓ 常见问题
Q1:如何切换存储方案?
方法1:后台配置(推荐)
系统管理 → 文件管理 → 存储配置 → 选择存储类型方法2:代码配置
// 修改配置文件
// config/storage.php
return [
'type' => 'qiniu', // 改为 'alioss'、'local' 等
];注意事项:
- 切换存储方案后,已上传的文件不会自动迁移
- 需要手动迁移文件或重新上传
Q2:文件秒传不生效?
可能原因:
- 文件命名策略不是 hash
- 文件内容不同(即使文件名相同)
解决方法:
// 确保使用 hash 命名
$filename = Storage::name($filePath, 'jpg', 'image', 'md5');
// 不要使用 'date' 命名策略Q3:如何获取文件访问 URL?
方法1:使用 url() 方法
$url = Storage::instance()->url($filename);
// 返回:https://example.com/image/abc123.jpg方法2:从上传结果获取
$result = Storage::instance()->set($filename, $content);
$url = $result['url'];
// 返回:https://example.com/image/abc123.jpgQ4:云存储配置失败?
可能原因:
- 配置参数错误
- 网络连接问题
- 权限不足
解决方法:
// 1. 检查配置参数
$config = sysconf('storage');
// 确保 access_key、secret_key 等参数正确
// 2. 测试连接
try {
$result = Storage::instance()->has('test.txt');
} catch (\Exception $e) {
echo '连接失败:' . $e->getMessage();
}Q5:如何实现文件下载?
方法1:直接返回文件内容
public function download()
{
$filename = input('filename');
$content = Storage::instance()->get($filename);
// 设置响应头
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($filename) . '"');
echo $content;
}方法2:重定向到文件 URL
public function download()
{
$filename = input('filename');
$url = Storage::instance()->url($filename);
// 重定向到文件 URL
return redirect($url);
}Q6:如何批量迁移文件?
迁移脚本示例:
<?php
// 从本地存储迁移到云存储
$localStorage = LocalStorage::instance();
$cloudStorage = QiniuStorage::instance();
// 获取所有文件列表
$files = $localStorage->list('upload');
foreach ($files as $file) {
// 读取本地文件
$content = $localStorage->get($file);
// 上传到云存储
$cloudStorage->set($file, $content);
// 删除本地文件(可选)
// $localStorage->del($file);
}Q7:如何限制文件大小?
方法1:后台配置
系统管理 → 文件管理 → 存储配置 → 最大文件大小方法2:代码验证
$maxSize = sysconf('storage.max_size', 2097152); // 默认 2MB
if ($file->getSize() > $maxSize) {
$this->error('文件大小超过限制!');
}Q8:如何限制文件类型?
方法1:后台配置
系统管理 → 文件管理 → 存储配置 → 允许的文件类型方法2:代码验证
$allowExts = str2arr(sysconf('storage.allow_exts', 'jpg,png,gif'));
$ext = strtolower($file->extension());
if (!in_array($ext, $allowExts)) {
$this->error('不支持的文件类型!');
}后续更新:根据使用情况,会不定时增加其他存储支持,具体调用参数一致,可根据对应存储驱动调用即可。
