doc: README.MD add chunk file upload instructions
This commit is contained in:
@@ -16,6 +16,11 @@
|
||||
- 🛡️ 内置安全防护(路径遍历攻击防护、点文件访问控制)
|
||||
- 💾 智能缓存支持(ETag、Last-Modified、Cache-Control)
|
||||
- 🎯 自动 Content-Type 检测
|
||||
- 📤 **大文件分片上传**:支持大文件分片上传、断点续传、秒传、自动合并
|
||||
- 🔄 **断点续传**:支持上传中断后继续上传
|
||||
- ⚡ **秒传功能**:基于文件哈希的秒传检测
|
||||
- 🗂️ **文件去重**:基于文件哈希的去重机制
|
||||
- 💾 **数据库存储**:使用 SQLite 存储文件元数据
|
||||
|
||||
## 安装
|
||||
|
||||
@@ -359,6 +364,393 @@ v-hono/
|
||||
└── sample.json # JSON文件
|
||||
```
|
||||
|
||||
## 大文件分片上传系统
|
||||
|
||||
### 概述
|
||||
|
||||
V-Hono 大文件分片上传系统是一个基于 V 语言和 Hono 框架构建的高性能文件上传解决方案。支持大文件分片上传、断点续传、秒传、自动合并等功能。
|
||||
|
||||
### 主要特性
|
||||
|
||||
- ✅ **分片上传**:支持大文件分片上传,默认分片大小 1MB
|
||||
- ✅ **断点续传**:支持上传中断后继续上传
|
||||
- ✅ **秒传功能**:基于文件哈希的秒传检测
|
||||
- ✅ **自动合并**:所有分片上传完成后自动合并文件
|
||||
- ✅ **文件去重**:基于文件哈希的去重机制
|
||||
- ✅ **数据库存储**:使用 SQLite 存储文件元数据
|
||||
- ✅ **RESTful API**:完整的 REST API 接口
|
||||
- ✅ **Web 界面**:提供友好的 Web 上传界面
|
||||
|
||||
### 系统架构
|
||||
|
||||
```
|
||||
前端 (Web/移动端)
|
||||
↓
|
||||
V-Hono 服务器
|
||||
↓
|
||||
分片存储 (./uploads/chunks/)
|
||||
↓
|
||||
文件合并 (./uploads/files/)
|
||||
↓
|
||||
数据库 (SQLite)
|
||||
```
|
||||
|
||||
### 安装和运行
|
||||
|
||||
#### 1. 环境要求
|
||||
|
||||
- V 语言 0.4.x 或更高版本
|
||||
- Windows/Linux/macOS
|
||||
|
||||
#### 2. 启动服务器
|
||||
|
||||
```bash
|
||||
# 克隆项目
|
||||
git clone <repository-url>
|
||||
cd v-hono
|
||||
|
||||
# 启动分片上传服务器
|
||||
v run chunk_upload_example.v
|
||||
```
|
||||
|
||||
服务器将在 `http://localhost:8080` 启动。
|
||||
|
||||
#### 3. 访问 Web 界面
|
||||
|
||||
打开浏览器访问 `http://localhost:8080` 即可使用 Web 上传界面。
|
||||
|
||||
### API 接口文档
|
||||
|
||||
#### 1. 分片上传接口
|
||||
|
||||
**接口地址:** `POST /upload/chunk`
|
||||
|
||||
**请求参数:**
|
||||
- `file_hash` (string): 文件哈希值
|
||||
- `chunk_index` (int): 分片索引,从 0 开始
|
||||
- `filename` (string): 原始文件名
|
||||
- `file_size` (int): 文件总大小(字节)
|
||||
- `chunk_size` (int): 分片大小(字节)
|
||||
- `chunk_hash` (string): 分片哈希值
|
||||
- `chunk` (file): 分片文件数据
|
||||
|
||||
**响应格式:**
|
||||
|
||||
上传完成(自动合并):
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"all_chunk_uploaded": true,
|
||||
"file_path": ".\\uploads\\files\\xxx.zip",
|
||||
"file_uuid": "xxx-xxx-xxx",
|
||||
"message": "File merged successfully"
|
||||
}
|
||||
```
|
||||
|
||||
上传中:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"chunk_index": 1,
|
||||
"all_chunk_uploaded": false,
|
||||
"message": "Chunk uploaded successfully"
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 分片存在检查接口
|
||||
|
||||
**接口地址:** `GET /upload/chunk_exists`
|
||||
|
||||
**请求参数:**
|
||||
- `file_hash` (string): 文件哈希值
|
||||
- `chunk_index` (int): 分片索引
|
||||
- `chunk_hash` (string): 分片哈希值
|
||||
- `file_size` (int): 文件总大小
|
||||
- `trunk_size` (int): 分片大小
|
||||
|
||||
**响应格式:**
|
||||
```json
|
||||
{
|
||||
"exists": true,
|
||||
"all_chunk_uploaded": false
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 上传状态查询接口
|
||||
|
||||
**接口地址:** `GET /upload/status`
|
||||
|
||||
**请求参数:**
|
||||
- `file_hash` (string): 文件哈希值
|
||||
|
||||
**响应格式:**
|
||||
```json
|
||||
{
|
||||
"file_hash": "xxx",
|
||||
"filename": "example.zip",
|
||||
"total_chunks": 0,
|
||||
"file_size": 1048576,
|
||||
"chunk_size": 2097152,
|
||||
"uploaded_chunks": [0, 1, 2],
|
||||
"status": "uploading",
|
||||
"created_at": 1640995200,
|
||||
"updated_at": 1640995300
|
||||
}
|
||||
```
|
||||
|
||||
#### 4. 已上传分片查询接口
|
||||
|
||||
**接口地址:** `GET /upload/chunks`
|
||||
|
||||
**请求参数:**
|
||||
- `file_hash` (string): 文件哈希值
|
||||
|
||||
**响应格式:**
|
||||
```json
|
||||
{
|
||||
"uploaded_chunks": [0, 1, 2],
|
||||
"total_chunks": 5,
|
||||
"completed": false
|
||||
}
|
||||
```
|
||||
|
||||
#### 5. 文件管理接口
|
||||
|
||||
##### 获取所有文件
|
||||
**接口地址:** `GET /api/files`
|
||||
|
||||
##### 根据 UUID 获取文件
|
||||
**接口地址:** `GET /api/files/{uuid}`
|
||||
|
||||
##### 根据哈希获取文件
|
||||
**接口地址:** `GET /api/files/hash/{hash}`
|
||||
|
||||
##### 删除文件
|
||||
**接口地址:** `DELETE /api/files/{uuid}`
|
||||
|
||||
### 配置说明
|
||||
|
||||
#### ChunkUploadConfig 配置项
|
||||
|
||||
```v
|
||||
pub struct ChunkUploadConfig {
|
||||
chunk_size: int = 1024 * 1024 // 默认分片大小 1MB
|
||||
max_file_size: int = 1024 * 1024 * 1024 // 最大文件大小 1GB
|
||||
temp_dir: string = './uploads/chunks' // 临时分片目录
|
||||
upload_dir: string = './uploads/files' // 最终文件目录
|
||||
cleanup_delay: int = 3600 // 清理延迟时间(秒)
|
||||
clear_chunks_on_complete: bool = false // 完成后是否清理分片
|
||||
db_path: string = './uploads/files.db' // 数据库文件路径
|
||||
}
|
||||
```
|
||||
|
||||
### 文件存储结构
|
||||
|
||||
```
|
||||
uploads/
|
||||
├── chunks/ # 分片文件目录
|
||||
│ └── {file_hash}/ # 按文件哈希分组
|
||||
│ └── {chunk_size}/ # 按分片大小分组
|
||||
│ ├── chunk_0.part # 分片文件
|
||||
│ ├── chunk_1.part
|
||||
│ └── ...
|
||||
├── files/ # 最终文件目录
|
||||
│ ├── {file_hash}.{ext} # 合并后的文件
|
||||
│ └── ...
|
||||
└── files.db # SQLite 数据库文件
|
||||
```
|
||||
|
||||
### 使用示例
|
||||
|
||||
#### 1. 前端 JavaScript 示例
|
||||
|
||||
```javascript
|
||||
// 计算文件哈希
|
||||
async function calculateFileHash(file) {
|
||||
return new Promise(resolve => {
|
||||
const spark = new SparkMD5.ArrayBuffer();
|
||||
const reader = new FileReader();
|
||||
reader.onload = e => {
|
||||
spark.append(e.target.result);
|
||||
resolve(spark.end());
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
});
|
||||
}
|
||||
|
||||
// 上传分片
|
||||
async function uploadChunk(file, chunk, { fileHash, chunkIndex, chunkHash }) {
|
||||
const form = new FormData();
|
||||
form.append('file_hash', fileHash);
|
||||
form.append('chunk_index', chunkIndex);
|
||||
form.append('filename', file.name);
|
||||
form.append('file_size', file.size);
|
||||
form.append('chunk_size', CHUNK_SIZE);
|
||||
form.append('chunk_hash', chunkHash);
|
||||
form.append('chunk', chunk);
|
||||
|
||||
const response = await fetch('/upload/chunk', {
|
||||
method: 'POST',
|
||||
body: form
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.all_chunk_uploaded) {
|
||||
console.log('上传完成,文件已合并:', result.file_path);
|
||||
return true; // 上传完成
|
||||
}
|
||||
|
||||
return false; // 继续上传
|
||||
}
|
||||
|
||||
// 分片上传主函数
|
||||
async function uploadFile(file) {
|
||||
const fileHash = await calculateFileHash(file);
|
||||
const chunkSize = 2 * 1024 * 1024; // 2MB
|
||||
const totalChunks = Math.ceil(file.size / chunkSize);
|
||||
|
||||
for (let i = 0; i < totalChunks; i++) {
|
||||
const chunk = file.slice(i * chunkSize, (i + 1) * chunkSize);
|
||||
const chunkHash = await calculateFileHash(chunk);
|
||||
|
||||
const completed = await uploadChunk(file, chunk, {
|
||||
fileHash,
|
||||
chunkIndex: i,
|
||||
chunkHash
|
||||
});
|
||||
|
||||
if (completed) {
|
||||
break; // 上传完成
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. cURL 示例
|
||||
|
||||
```bash
|
||||
# 上传分片
|
||||
curl -X POST http://localhost:8080/upload/chunk \
|
||||
-F "file_hash=abc123" \
|
||||
-F "chunk_index=0" \
|
||||
-F "filename=large_file.zip" \
|
||||
-F "file_size=10485760" \
|
||||
-F "chunk_size=2097152" \
|
||||
-F "chunk_hash=def456" \
|
||||
-F "chunk=@chunk_0.part"
|
||||
|
||||
# 检查分片是否存在
|
||||
curl "http://localhost:8080/upload/chunk_exists?file_hash=abc123&chunk_index=0&chunk_hash=def456&file_size=10485760&trunk_size=2097152"
|
||||
```
|
||||
|
||||
### 核心算法
|
||||
|
||||
#### 1. 分片合并判断
|
||||
|
||||
系统使用以下逻辑判断是否所有分片都已上传:
|
||||
|
||||
```v
|
||||
// 计算理论上需要的分片数量
|
||||
expected_chunks := (expected_file_size + u64(chunk_size) - 1) / u64(chunk_size)
|
||||
|
||||
// 只有当分片数量达到预期且总大小 >= 文件大小时,才认为上传完成
|
||||
if chunk_count >= int(expected_chunks) && total_chunk_size >= expected_file_size {
|
||||
all_chunk_uploaded = true
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 文件去重机制
|
||||
|
||||
- 基于文件哈希进行去重
|
||||
- 相同哈希的文件只存储一份
|
||||
- 支持同一文件的不同文件名
|
||||
|
||||
#### 3. 秒传检测
|
||||
|
||||
- 前端计算文件哈希
|
||||
- 后端检查文件是否已存在
|
||||
- 如果存在则直接返回文件信息,无需上传
|
||||
|
||||
### 性能优化
|
||||
|
||||
#### 1. 内存管理
|
||||
|
||||
- 分片文件存储在磁盘,不占用大量内存
|
||||
- 上传状态使用内存缓存,提高查询速度
|
||||
- 支持配置清理策略,自动清理临时文件
|
||||
|
||||
#### 2. 并发处理
|
||||
|
||||
- 支持多用户同时上传
|
||||
- 分片级别的并发控制
|
||||
- 文件级别的锁机制
|
||||
|
||||
#### 3. 错误处理
|
||||
|
||||
- 网络异常自动重试
|
||||
- 分片损坏自动重新上传
|
||||
- 完整的错误日志记录
|
||||
|
||||
### 监控和日志
|
||||
|
||||
#### 1. 调试日志
|
||||
|
||||
系统提供详细的调试日志,包括:
|
||||
- 分片上传状态
|
||||
- 文件合并过程
|
||||
- 错误信息追踪
|
||||
|
||||
#### 2. 性能监控
|
||||
|
||||
- 上传速度统计
|
||||
- 分片成功率
|
||||
- 系统资源使用情况
|
||||
|
||||
### 故障排除
|
||||
|
||||
#### 1. 常见问题
|
||||
|
||||
**Q: 上传大文件时出现内存不足**
|
||||
A: 检查分片大小配置,建议设置为 1-5MB
|
||||
|
||||
**Q: 分片上传后文件合并失败**
|
||||
A: 检查磁盘空间和文件权限
|
||||
|
||||
**Q: 秒传功能不工作**
|
||||
A: 确认前端哈希算法与后端一致
|
||||
|
||||
#### 2. 日志分析
|
||||
|
||||
查看服务器日志获取详细错误信息:
|
||||
```bash
|
||||
# 启动时查看详细日志
|
||||
v run chunk_upload_example.v
|
||||
```
|
||||
|
||||
### 扩展功能
|
||||
|
||||
#### 1. 云存储集成
|
||||
|
||||
可以扩展支持:
|
||||
- AWS S3
|
||||
- 阿里云 OSS
|
||||
- 腾讯云 COS
|
||||
|
||||
#### 2. 文件处理
|
||||
|
||||
可以添加:
|
||||
- 图片压缩
|
||||
- 视频转码
|
||||
- 文档预览
|
||||
|
||||
#### 3. 权限控制
|
||||
|
||||
可以集成:
|
||||
- 用户认证
|
||||
- 文件权限
|
||||
- 访问控制
|
||||
|
||||
## 性能特性
|
||||
|
||||
- **混合路由算法**:静态路由 O(1) 查找,动态路由正则匹配
|
||||
|
||||
Reference in New Issue
Block a user