# Chat-Room 文件传输文档
## 📋 概述
Chat-Room支持完整的文件传输功能,用户可以在聊天组中上传和下载文件。系统支持多种文件类型,提供文件大小限制、类型检查、进度显示等功能,确保文件传输的安全性和可靠性。
## 🏗️ 文件传输架构
### 文件传输架构图
```mermaid
graph TB
subgraph "客户端层"
UPLOAD[文件上传界面]
DOWNLOAD[文件下载界面]
PROGRESS[进度显示]
FILE_LIST[文件列表]
end
subgraph "网络传输层"
CHUNK[分块传输]
COMPRESS[压缩处理]
VALIDATE[数据验证]
end
subgraph "服务器处理层"
FILE_HANDLER[文件处理器
FileHandler]
VALIDATOR[文件验证器
FileValidator]
STORAGE[存储管理器
StorageManager]
end
subgraph "数据存储层"
FILE_DB[文件数据库
files表]
FILE_SYSTEM[文件系统
本地存储]
end
UPLOAD --> CHUNK
DOWNLOAD --> CHUNK
CHUNK --> COMPRESS
COMPRESS --> VALIDATE
VALIDATE --> FILE_HANDLER
FILE_HANDLER --> VALIDATOR
FILE_HANDLER --> STORAGE
VALIDATOR --> FILE_DB
STORAGE --> FILE_SYSTEM
STORAGE --> FILE_DB
FILE_LIST --> FILE_DB
PROGRESS --> CHUNK
```
### 文件传输流程
```mermaid
sequenceDiagram
participant C as 客户端
participant S as 服务器
participant FH as 文件处理器
participant V as 文件验证器
participant SM as 存储管理器
participant FS as 文件系统
participant DB as 数据库
Note over C,DB: 文件上传流程
C->>S: 发送上传请求
S->>FH: 处理上传请求
FH->>V: 验证文件信息
V->>V: 检查文件类型和大小
alt 验证通过
V-->>FH: 验证成功
FH->>SM: 准备存储空间
SM->>FS: 创建存储目录
FH-->>C: 发送上传确认
loop 分块传输
C->>S: 发送文件块
S->>FH: 处理文件块
FH->>SM: 写入文件块
SM->>FS: 保存到磁盘
FH-->>C: 确认块接收
end
FH->>V: 验证文件完整性
FH->>DB: 记录文件信息
FH-->>C: 上传完成
else 验证失败
V-->>FH: 验证失败
FH-->>C: 上传拒绝
end
Note over C,DB: 文件下载流程
C->>S: 发送下载请求
S->>FH: 处理下载请求
FH->>DB: 查询文件信息
FH->>V: 验证下载权限
alt 权限验证通过
FH->>SM: 读取文件
SM->>FS: 从磁盘读取
loop 分块传输
SM-->>FH: 返回文件块
FH-->>S: 发送文件块
S-->>C: 传输文件块
end
FH-->>C: 下载完成
else 权限验证失败
FH-->>C: 下载拒绝
end
```
## 📁 文件处理器实现
### 核心文件处理器 (server/core/file_handler.py)
```python
class FileHandler:
"""文件处理器核心类"""
def __init__(self, config: dict):
self.config = config
self.validator = FileValidator(config)
self.storage_manager = StorageManager(config)
self.upload_dir = config.get('upload_dir', 'server/data/files/uploads')
self.chunk_size = config.get('chunk_size', 8192)
def handle_file_upload(self, user_id: int, group_id: int,
file_info: dict, file_data: bytes) -> Tuple[bool, str]:
"""处理文件上传"""
try:
# 验证文件信息
is_valid, error_msg = self.validator.validate_upload(file_info, user_id, group_id)
if not is_valid:
return False, error_msg
# 生成文件ID和存储路径
file_id = self._generate_file_id()
storage_path = self.storage_manager.get_storage_path(file_id, file_info['filename'])
# 保存文件到磁盘
success = self.storage_manager.save_file(storage_path, file_data)
if not success:
return False, "文件保存失败"
# 记录文件信息到数据库
file_record = {
'file_id': file_id,
'group_id': group_id,
'uploader_id': user_id,
'original_filename': file_info['filename'],
'stored_filename': os.path.basename(storage_path),
'file_size': len(file_data),
'file_type': self._get_file_type(file_info['filename']),
'upload_time': datetime.now()
}
from server.database.models import File
file_obj = File(**file_record)
file_obj.save()
return True, f"文件上传成功,文件ID: {file_id}"
except Exception as e:
logger.error(f"文件上传处理失败: {e}")
return False, "文件上传处理失败"
def handle_file_download(self, user_id: int, file_id: str) -> Tuple[bool, str, bytes]:
"""处理文件下载"""
try:
# 查询文件信息
from server.database.models import File
file_obj = File.get_by_file_id(file_id)
if not file_obj:
return False, "文件不存在", b''
# 验证下载权限
has_permission = self.validator.validate_download_permission(user_id, file_obj)
if not has_permission:
return False, "没有下载权限", b''
# 读取文件数据
storage_path = self.storage_manager.get_file_path(file_obj.stored_filename)
file_data = self.storage_manager.read_file(storage_path)
if file_data is None:
return False, "文件读取失败", b''
return True, "文件下载成功", file_data
except Exception as e:
logger.error(f"文件下载处理失败: {e}")
return False, "文件下载处理失败", b''
def list_group_files(self, group_id: int, user_id: int) -> List[dict]:
"""列出聊天组文件"""
try:
from server.database.models import File
files = File.get_group_files(group_id)
file_list = []
for file_obj in files:
file_info = {
'file_id': file_obj.file_id,
'original_filename': file_obj.original_filename,
'file_size': file_obj.file_size,
'file_type': file_obj.file_type,
'uploader': file_obj.uploader.username,
'upload_time': file_obj.upload_time.isoformat(),
'can_download': self.validator.validate_download_permission(user_id, file_obj)
}
file_list.append(file_info)
return file_list
except Exception as e:
logger.error(f"获取文件列表失败: {e}")
return []
```
### 文件验证器 (server/core/file_validator.py)
```python
class FileValidator:
"""文件验证器"""
def __init__(self, config: dict):
self.config = config
self.max_file_size = config.get('max_file_size', 10 * 1024 * 1024) # 10MB
self.allowed_types = config.get('allowed_types', [])
self.blocked_types = config.get('blocked_types', [])
def validate_upload(self, file_info: dict, user_id: int, group_id: int) -> Tuple[bool, str]:
"""验证文件上传"""
# 检查文件名
if not self._validate_filename(file_info['filename']):
return False, "文件名包含非法字符"
# 检查文件大小
if file_info['file_size'] > self.max_file_size:
return False, f"文件大小超过限制({self.max_file_size}字节)"
# 检查文件类型
if not self._validate_file_type(file_info['filename']):
return False, "不支持的文件类型"
# 检查用户权限
if not self._validate_upload_permission(user_id, group_id):
return False, "没有上传权限"
return True, "验证通过"
def validate_download_permission(self, user_id: int, file_obj) -> bool:
"""验证下载权限"""
# 检查用户是否在文件所属聊天组中
from server.database.models import GroupMember
is_member = GroupMember.is_user_in_group(user_id, file_obj.group_id)
return is_member
def _validate_filename(self, filename: str) -> bool:
"""验证文件名"""
# 检查文件名长度
if len(filename) > 255:
return False
# 检查非法字符
illegal_chars = ['<', '>', ':', '"', '|', '?', '*', '\\', '/']
for char in illegal_chars:
if char in filename:
return False
return True
def _validate_file_type(self, filename: str) -> bool:
"""验证文件类型"""
file_ext = os.path.splitext(filename)[1].lower()
# 检查是否在禁止列表中
if file_ext in self.blocked_types:
return False
# 如果有允许列表,检查是否在允许列表中
if self.allowed_types and file_ext not in self.allowed_types:
return False
return True
```
### 存储管理器 (server/core/storage_manager.py)
```python
class StorageManager:
"""存储管理器"""
def __init__(self, config: dict):
self.config = config
self.base_dir = config.get('upload_dir', 'server/data/files/uploads')
self.ensure_base_dir()
def get_storage_path(self, file_id: str, filename: str) -> str:
"""获取文件存储路径"""
# 按日期组织目录结构
now = datetime.now()
date_path = now.strftime("%Y/%m/%d")
# 创建目录
full_dir = os.path.join(self.base_dir, date_path)
os.makedirs(full_dir, exist_ok=True)
# 生成存储文件名
file_ext = os.path.splitext(filename)[1]
stored_filename = f"{file_id}{file_ext}"
return os.path.join(full_dir, stored_filename)
def save_file(self, file_path: str, file_data: bytes) -> bool:
"""保存文件到磁盘"""
try:
with open(file_path, 'wb') as f:
f.write(file_data)
return True
except Exception as e:
logger.error(f"文件保存失败: {e}")
return False
def read_file(self, file_path: str) -> Optional[bytes]:
"""从磁盘读取文件"""
try:
if not os.path.exists(file_path):
return None
with open(file_path, 'rb') as f:
return f.read()
except Exception as e:
logger.error(f"文件读取失败: {e}")
return None
def delete_file(self, file_path: str) -> bool:
"""删除文件"""
try:
if os.path.exists(file_path):
os.remove(file_path)
return True
except Exception as e:
logger.error(f"文件删除失败: {e}")
return False
```
## 🗄️ 文件数据模型
### 文件信息表结构
```sql
CREATE TABLE files (
id INTEGER PRIMARY KEY AUTOINCREMENT,
file_id TEXT UNIQUE NOT NULL,
group_id INTEGER NOT NULL,
uploader_id INTEGER NOT NULL,
original_filename TEXT NOT NULL,
stored_filename TEXT NOT NULL,
file_size INTEGER NOT NULL,
file_type TEXT NOT NULL,
file_hash TEXT,
upload_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
download_count INTEGER DEFAULT 0,
is_deleted BOOLEAN DEFAULT 0,
FOREIGN KEY (group_id) REFERENCES chat_groups (id),
FOREIGN KEY (uploader_id) REFERENCES users (id)
);
-- 创建索引
CREATE INDEX idx_files_group_id ON files (group_id, upload_time DESC);
CREATE INDEX idx_files_uploader ON files (uploader_id, upload_time DESC);
CREATE INDEX idx_files_file_id ON files (file_id);
```
### 文件传输记录表
```sql
CREATE TABLE file_transfers (
id INTEGER PRIMARY KEY AUTOINCREMENT,
file_id TEXT NOT NULL,
user_id INTEGER NOT NULL,
transfer_type TEXT NOT NULL, -- 'upload' or 'download'
transfer_status TEXT NOT NULL, -- 'started', 'completed', 'failed'
bytes_transferred INTEGER DEFAULT 0,
total_bytes INTEGER NOT NULL,
start_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
end_time TIMESTAMP,
error_message TEXT,
FOREIGN KEY (file_id) REFERENCES files (file_id),
FOREIGN KEY (user_id) REFERENCES users (id)
);
```
## ⚙️ 文件传输配置
### 服务器文件配置 (config/server_config.yaml)
```yaml
# 文件传输配置
file_transfer:
# 基础设置
enabled: true
max_file_size: 10485760 # 10MB
chunk_size: 8192 # 8KB
# 存储设置
upload_dir: "server/data/files/uploads"
temp_dir: "server/data/files/temp"
auto_cleanup: true
cleanup_interval: 3600 # 1小时
# 文件类型设置
allowed_types:
- ".txt"
- ".pdf"
- ".doc"
- ".docx"
- ".xls"
- ".xlsx"
- ".ppt"
- ".pptx"
- ".jpg"
- ".jpeg"
- ".png"
- ".gif"
- ".bmp"
- ".zip"
- ".rar"
- ".7z"
- ".tar"
- ".gz"
blocked_types:
- ".exe"
- ".bat"
- ".cmd"
- ".scr"
- ".com"
- ".pif"
# 安全设置
scan_uploads: true
quarantine_suspicious: true
max_files_per_user: 100
max_files_per_group: 1000
# 性能设置
max_concurrent_uploads: 10
max_concurrent_downloads: 20
transfer_timeout: 300 # 5分钟
# 备份设置
backup_enabled: false
backup_interval: 86400 # 24小时
backup_retention: 30 # 30天
```
### 客户端文件配置 (config/client_config.yaml)
```yaml
# 文件传输配置
file_transfer:
# 下载设置
download_dir: "client/Downloads"
auto_create_dirs: true
overwrite_existing: false
# 传输设置
chunk_size: 8192
max_concurrent_downloads: 3
resume_downloads: true
# 确认设置
confirm_downloads: true
confirm_large_files: true
large_file_threshold: 5242880 # 5MB
# 进度显示
show_progress: true
progress_update_interval: 1 # 1秒
```
## 🚀 文件传输使用指南
### 文件上传
```bash
# 上传单个文件
/send_files document.pdf
# 上传多个文件
/send_files document.pdf image.jpg data.xlsx
# 上传指定路径的文件
/send_files /home/user/documents/report.pdf
# 上传时显示进度
/send_files --progress document.pdf
```
### 文件下载
```bash
# 列出可下载文件
/recv_files -l
/recv_files --list
# 下载指定文件
/recv_files -n document.pdf
/recv_files --name document.pdf
# 下载指定ID的文件
/recv_files -i file_12345
/recv_files --id file_12345
# 下载所有文件
/recv_files -a
/recv_files --all
# 下载到指定目录
/recv_files -n document.pdf -d /home/user/downloads
```
### 文件管理
```bash
# 查看文件详情
/file_info file_12345
# 删除文件(仅上传者和管理员)
/delete_file file_12345
# 搜索文件
/search_files keyword
# 查看上传历史
/upload_history
# 查看下载历史
/download_history
```
## 📊 文件传输监控
### 传输状态监控
```mermaid
graph TB
subgraph "传输监控指标"
ACTIVE[活跃传输数]
SPEED[传输速度]
SUCCESS[成功率]
ERROR[错误率]
STORAGE[存储使用量]
BANDWIDTH[带宽使用]
end
subgraph "监控工具"
DASHBOARD[监控面板]
ALERTS[告警系统]
LOGS[日志分析]
end
ACTIVE --> DASHBOARD
SPEED --> DASHBOARD
SUCCESS --> DASHBOARD
ERROR --> ALERTS
STORAGE --> ALERTS
BANDWIDTH --> DASHBOARD
DASHBOARD --> LOGS
ALERTS --> LOGS
```
### 性能优化建议
1. **传输优化**
- 使用适当的分块大小
- 实现断点续传功能
- 并行传输多个文件
2. **存储优化**
- 按日期组织文件目录
- 定期清理临时文件
- 实现文件压缩存储
3. **安全优化**
- 文件类型白名单控制
- 病毒扫描集成
- 文件完整性校验
4. **用户体验优化**
- 实时进度显示
- 传输速度显示
- 错误重试机制
这个文件传输文档提供了完整的文件传输架构、实现细节、配置管理和使用指南,帮助开发者理解和使用Chat-Room的文件传输功能。