1. 为什么需要局域网文件与剪贴板共享工具
在日常办公和团队协作中,我们经常会遇到这样的场景:同事之间需要频繁传输文件,或者需要在不同设备间同步剪贴板内容。传统做法是使用U盘、数据线或者通过聊天工具发送文件,但这些方式都存在明显缺陷:
- U盘/数据线传输:需要物理接触,跨设备操作不便,且存在病毒传播风险
- 聊天工具传输:需要登录账号,文件大小受限,且历史文件难以管理
- 剪贴板同步:完全无法通过传统方式实现,只能手动复制粘贴
特别是在局域网环境下,这些痛点更加明显。想象一下这样的场景:你在会议室用笔记本演示,突然需要把手机上的截图传到电脑;或者你在台式机复制了一段代码,想在笔记本上直接粘贴使用。这时候,一个轻量级的局域网共享工具就能极大提升效率。
2. FastAPI作为解决方案的优势
FastAPI是一个现代、快速(高性能)的Python Web框架,特别适合构建这类工具,主要优势体现在:
2.1 性能与并发能力
FastAPI基于Starlette(用于异步请求)和Pydantic(用于数据验证),性能接近NodeJS和Go。实测在普通开发机上就能轻松处理1000+并发请求,完全满足局域网内多设备共享的需求。
2.2 开发效率
用FastAPI搭建基础API服务通常只需要几分钟。比如实现文件上传接口,核心代码不超过10行:
python复制from fastapi import FastAPI, UploadFile
from fastapi.staticfiles import StaticFiles
app = FastAPI()
app.mount("/files", StaticFiles(directory="uploads"), name="uploads")
@app.post("/upload")
async def upload_file(file: UploadFile):
contents = await file.read()
with open(f"uploads/{file.filename}", "wb") as f:
f.write(contents)
return {"filename": file.filename}
2.3 自动文档支持
FastAPI自动生成交互式API文档(Swagger UI和ReDoc),方便调试和团队协作,这对内部工具尤为重要。
3. 完整实现方案
3.1 基础环境准备
首先确保Python环境(建议3.7+),然后安装依赖:
bash复制pip install fastapi uvicorn python-multipart
3.2 文件共享服务实现
创建main.py文件,实现以下核心功能:
python复制from fastapi import FastAPI, UploadFile, HTTPException
from fastapi.staticfiles import StaticFiles
from pathlib import Path
import uvicorn
import os
app = FastAPI()
UPLOAD_DIR = "shared_files"
Path(UPLOAD_DIR).mkdir(exist_ok=True)
# 挂载静态文件目录
app.mount("/files", StaticFiles(directory=UPLOAD_DIR), name="files")
@app.post("/upload")
async def upload_file(file: UploadFile):
file_path = os.path.join(UPLOAD_DIR, file.filename)
try:
contents = await file.read()
with open(file_path, "wb") as f:
f.write(contents)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
return {"status": "success", "filepath": f"/files/{file.filename}"}
@app.get("/list")
async def list_files():
return {"files": os.listdir(UPLOAD_DIR)}
3.3 剪贴板同步实现
添加剪贴板同步功能需要前端配合,这里给出后端API实现:
python复制from pydantic import BaseModel
class ClipboardData(BaseModel):
text: str
clipboard_content = ""
@app.post("/clipboard")
async def update_clipboard(data: ClipboardData):
global clipboard_content
clipboard_content = data.text
return {"status": "updated"}
@app.get("/clipboard")
async def get_clipboard():
return {"content": clipboard_content}
3.4 前端界面集成
使用HTML+JavaScript实现简单界面(可保存为templates/index.html):
html复制<!DOCTYPE html>
<html>
<head>
<title>局域网共享工具</title>
<script>
async function uploadFile() {
const fileInput = document.getElementById('fileInput');
const formData = new FormData();
formData.append('file', fileInput.files[0]);
const response = await fetch('/upload', {
method: 'POST',
body: formData
});
const result = await response.json();
alert(`文件已上传: ${result.filepath}`);
}
async function syncClipboard() {
const text = await navigator.clipboard.readText();
await fetch('/clipboard', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({text: text})
});
alert('剪贴板已同步');
}
</script>
</head>
<body>
<h1>局域网共享工具</h1>
<div>
<h2>文件共享</h2>
<input type="file" id="fileInput">
<button onclick="uploadFile()">上传</button>
</div>
<div>
<h2>剪贴板同步</h2>
<button onclick="syncClipboard()">同步我的剪贴板</button>
</div>
</body>
</html>
4. 部署与使用技巧
4.1 启动服务
使用UVicorn运行服务:
bash复制uvicorn main:app --host 0.0.0.0 --port 8000 --reload
4.2 局域网访问
- 确保所有设备在同一局域网
- 在服务端查看本机IP(Windows:
ipconfig,Mac/Linux:ifconfig) - 其他设备通过
http://[服务端IP]:8000访问
4.3 实用技巧
- 开机自启:可以将服务设置为系统服务或使用PM2管理
- 权限控制:添加简单密码验证(FastAPI的HTTPBasic)
- 文件清理:添加定时任务清理旧文件
- 跨平台剪贴板:不同平台剪贴板API不同,可能需要平台特定代码
5. 性能优化与安全建议
5.1 性能优化
- 对大文件上传使用流式处理:
python复制@app.post("/upload/large")
async def upload_large_file(file: UploadFile):
file_path = os.path.join(UPLOAD_DIR, file.filename)
with open(file_path, "wb") as f:
while contents := await file.read(1024*1024): # 1MB chunks
f.write(contents)
return {"status": "success"}
- 使用背景任务处理耗时操作:
python复制from fastapi import BackgroundTasks
def write_file(filepath: str, contents: bytes):
with open(filepath, "wb") as f:
f.write(contents)
@app.post("/upload/async")
async def upload_async(
file: UploadFile,
background_tasks: BackgroundTasks
):
file_path = os.path.join(UPLOAD_DIR, file.filename)
contents = await file.read()
background_tasks.add_task(write_file, file_path, contents)
return {"status": "processing"}
5.2 安全增强
- 文件类型检查:
python复制ALLOWED_TYPES = {"image/jpeg", "image/png", "application/pdf"}
@app.post("/upload/safe")
async def safe_upload(file: UploadFile):
if file.content_type not in ALLOWED_TYPES:
raise HTTPException(400, "File type not allowed")
# ...正常上传逻辑
- 文件大小限制(在FastAPI配置中设置):
python复制app = FastAPI(
max_upload_size=100 * 1024 * 1024 # 100MB
)
- CORS配置(允许特定域名访问):
python复制from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost"], # 按需修改
allow_methods=["*"],
allow_headers=["*"],
)
6. 进阶功能扩展
6.1 文件预览功能
对于常见文件类型(图片、PDF、文本)可以添加预览支持:
python复制from fastapi.responses import FileResponse
@app.get("/preview/{filename}")
async def preview_file(filename: str):
file_path = os.path.join(UPLOAD_DIR, filename)
if not os.path.exists(file_path):
raise HTTPException(404, "File not found")
if filename.lower().endswith(('.png', '.jpg', '.jpeg')):
return FileResponse(file_path, media_type="image/jpeg")
elif filename.lower().endswith('.pdf'):
return FileResponse(file_path, media_type="application/pdf")
else:
return FileResponse(file_path)
6.2 历史版本管理
使用GitPython实现简单的版本控制:
python复制import git
REPO_DIR = "shared_repo"
@app.post("/upload/versioned")
async def versioned_upload(file: UploadFile):
file_path = os.path.join(REPO_DIR, file.filename)
contents = await file.read()
# 初始化Git仓库(如果不存在)
if not os.path.exists(os.path.join(REPO_DIR, ".git")):
repo = git.Repo.init(REPO_DIR)
else:
repo = git.Repo(REPO_DIR)
# 写入文件并提交
with open(file_path, "wb") as f:
f.write(contents)
repo.index.add([file_path])
repo.index.commit(f"Update {file.filename}")
return {"status": "success", "commit": str(repo.head.commit)}
6.3 设备间消息通知
实现简单的设备间消息通知系统:
python复制from typing import Dict, List
from fastapi import WebSocket
active_connections: Dict[str, List[WebSocket]] = {}
@app.websocket("/ws/{device_id}")
async def websocket_endpoint(websocket: WebSocket, device_id: str):
await websocket.accept()
if device_id not in active_connections:
active_connections[device_id] = []
active_connections[device_id].append(websocket)
try:
while True:
data = await websocket.receive_text()
# 广播给其他设备
for dev_id, connections in active_connections.items():
if dev_id != device_id:
for connection in connections:
await connection.send_text(f"From {device_id}: {data}")
except:
active_connections[device_id].remove(websocket)
7. 实际使用中的经验分享
在实际部署和使用这个工具的过程中,我总结了以下几点经验:
-
文件命名冲突处理:
默认情况下,同名文件上传会直接覆盖。建议添加时间戳或随机字符串:python复制from datetime import datetime def get_unique_filename(filename): name, ext = os.path.splitext(filename) timestamp = datetime.now().strftime("%Y%m%d%H%M%S") return f"{name}_{timestamp}{ext}" -
剪贴板同步的延迟问题:
网页端剪贴板API需要用户交互才能触发,建议:- 添加"粘贴"按钮手动触发
- 或者使用Electron等桌面技术实现后台监听
-
局域网IP变化问题:
很多家庭网络的DHCP会导致设备IP变化,解决方法:- 在路由器中设置静态IP分配
- 使用mDNS(如
hostname.local访问) - 或者部署简单的IP广播发现服务
-
移动端适配:
在手机浏览器上,文件选择和剪贴板操作有所不同:- 对于文件上传,需要添加
accept属性限制文件类型 - iOS上的剪贴板访问有更多限制,可能需要用户手动粘贴
- 对于文件上传,需要添加
-
性能监控:
添加简单的性能监控端点,方便排查问题:python复制import psutil @app.get("/status") async def system_status(): return { "cpu": psutil.cpu_percent(), "memory": psutil.virtual_memory().percent, "disk": psutil.disk_usage('/').percent }
这个工具虽然简单,但在日常办公中确实能显著提升效率。特别是在需要频繁在多个设备间传递内容的场景下,避免了反复登录聊天工具或找数据线的麻烦。根据团队需求,还可以进一步扩展功能,比如添加用户系统、文件评论、审批流程等,使其成为一个完整的内部协作工具。
