1. 为什么我们需要一个局域网文件传输工具?
在日常工作和生活中,我们经常需要在不同设备间传输文件。传统的文件传输方式存在诸多痛点:
- 微信/QQ传输:文件会被压缩,特别是图片和视频质量损失严重
- 数据线连接:需要随身携带线材,插拔麻烦,不同设备接口还不兼容
- 云盘同步:需要登录账号,上传下载速度受限,隐私性无法保证
- 蓝牙传输:速度慢,连接不稳定,传输大文件简直是噩梦
我最近就遇到一个典型场景:在咖啡馆用手机拍了几张产品原型照片,需要立即传到电脑上处理。结果发现:
- 数据线忘带了
- 咖啡馆WiFi屏蔽了微信网页版
- 蓝牙传输一张3MB的照片花了近2分钟
这种时候,一个基于局域网的私有文件传输工具就能完美解决问题。它不依赖第三方服务,不需要额外硬件,只要设备在同一个网络下就能使用。
2. FastAPI为什么是理想选择?
在Python生态中,常见的Web框架有Flask、Django等,但我最终选择了FastAPI,原因如下:
2.1 性能优势
FastAPI基于Starlette(异步框架)和Pydantic,天生支持异步处理。在处理文件上传这类I/O密集型任务时,异步特性可以显著提高并发性能。实测在相同硬件条件下,FastAPI处理文件上传的吞吐量是Flask的3-5倍。
2.2 开发效率
FastAPI自带交互式API文档(Swagger UI和ReDoc),开发过程中可以实时测试接口。它的类型提示系统能在编码阶段就发现很多潜在错误,减少调试时间。
2.3 文件处理优雅
FastAPI对文件上传的支持非常完善。通过UploadFile类型,我们可以轻松获取文件名、内容类型和文件内容,还能利用异步流式处理大文件,避免内存溢出。
python复制from fastapi import FastAPI, UploadFile, File
app = FastAPI()
@app.post("/upload")
async def upload_file(file: UploadFile = File(...)):
contents = await file.read()
# 处理文件内容...
3. 从零搭建文件传输服务
3.1 环境准备
建议使用Python 3.8+版本。创建虚拟环境并安装依赖:
bash复制python -m venv venv
source venv/bin/activate # Linux/Mac
venv\Scripts\activate # Windows
pip install fastapi uvicorn python-multipart
注意:
python-multipart是必须的依赖包,没有它FastAPI无法处理文件上传表单。
3.2 核心代码实现
创建main.py文件,实现文件上传和下载功能:
python复制from fastapi import FastAPI, UploadFile, File, Request
from fastapi.responses import HTMLResponse, FileResponse
from fastapi.staticfiles import StaticFiles
import os
import uvicorn
app = FastAPI()
# 文件存储目录
UPLOAD_DIR = "uploads"
os.makedirs(UPLOAD_DIR, exist_ok=True)
# 剪贴板内容存储
clipboard_content = ""
@app.get("/", response_class=HTMLResponse)
async def home():
return """
<html>
<body>
<h1>文件传输服务</h1>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<button type="submit">上传</button>
</form>
</body>
</html>
"""
@app.post("/upload")
async def upload_file(file: UploadFile = File(...)):
file_path = os.path.join(UPLOAD_DIR, file.filename)
with open(file_path, "wb") as buffer:
buffer.write(await file.read())
return {"filename": file.filename}
@app.get("/download/{filename}")
async def download_file(filename: str):
file_path = os.path.join(UPLOAD_DIR, filename)
return FileResponse(file_path)
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
3.3 运行服务
启动服务:
bash复制uvicorn main:app --reload
访问http://localhost:8000即可看到上传界面。同一局域网下的其他设备可以通过电脑的IP地址访问,如http://192.168.1.100:8000。
4. 剪贴板同步功能实现
4.1 后端API
扩展main.py,添加剪贴板同步接口:
python复制@app.get("/clipboard")
async def get_clipboard():
return {"content": clipboard_content}
@app.post("/clipboard")
async def update_clipboard(request: Request):
global clipboard_content
data = await request.json()
clipboard_content = data.get("content", "")
return {"message": "剪贴板已更新"}
4.2 前端界面
更新首页HTML,添加剪贴板同步功能:
html复制<div>
<h2>剪贴板同步</h2>
<textarea id="clipboard" rows="5"></textarea>
<button onclick="syncClipboard()">同步到电脑</button>
<button onclick="getClipboard()">从电脑获取</button>
</div>
<script>
async function syncClipboard() {
const text = document.getElementById("clipboard").value;
await fetch("/clipboard", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({content: text})
});
}
async function getClipboard() {
const response = await fetch("/clipboard");
const data = await response.json();
document.getElementById("clipboard").value = data.content;
}
</script>
5. 实际使用中的注意事项
5.1 安全性考虑
- 仅在内网使用,不要将服务暴露到公网
- 可以添加简单的认证机制,如基础认证:
python复制from fastapi import Depends, HTTPException
from fastapi.security import HTTPBasic, HTTPBasicCredentials
security = HTTPBasic()
def authenticate(credentials: HTTPBasicCredentials = Depends(security)):
correct_username = "user"
correct_password = "pass"
if not (credentials.username == correct_username and credentials.password == correct_password):
raise HTTPException(status_code=401)
return credentials.username
@app.get("/secure")
async def secure_route(username: str = Depends(authenticate)):
return {"message": f"Hello {username}"}
5.2 文件管理
- 定期清理上传目录,避免磁盘空间被占满
- 处理文件名冲突,避免覆盖重要文件:
python复制import uuid
def get_unique_filename(filename: str) -> str:
ext = filename.split(".")[-1]
unique_name = f"{uuid.uuid4()}.{ext}"
return unique_name
5.3 性能优化
- 对于大文件,使用流式传输:
python复制@app.post("/upload-large")
async def upload_large_file(file: UploadFile = File(...)):
file_path = os.path.join(UPLOAD_DIR, file.filename)
with open(file_path, "wb") as buffer:
while chunk := await file.read(1024 * 1024): # 1MB chunks
buffer.write(chunk)
return {"filename": file.filename}
- 启用Gzip压缩:
bash复制uvicorn main:app --reload --gzip
6. 进阶功能扩展
6.1 文件列表展示
添加获取文件列表接口:
python复制@app.get("/files")
async def list_files():
files = os.listdir(UPLOAD_DIR)
return {"files": files}
前端可以展示可下载文件列表:
html复制<div id="file-list"></div>
<script>
async function loadFiles() {
const response = await fetch("/files");
const data = await response.json();
const fileList = document.getElementById("file-list");
fileList.innerHTML = data.files.map(file =>
`<div><a href="/download/${file}">${file}</a></div>`
).join("");
}
loadFiles();
</script>
6.2 剪贴板历史记录
使用列表存储剪贴板历史:
python复制clipboard_history = []
@app.post("/clipboard")
async def update_clipboard(request: Request):
global clipboard_content, clipboard_history
data = await request.json()
clipboard_content = data.get("content", "")
clipboard_history.append(clipboard_content)
if len(clipboard_history) > 10: # 保留最近10条记录
clipboard_history = clipboard_history[-10:]
return {"message": "剪贴板已更新"}
@app.get("/clipboard/history")
async def get_clipboard_history():
return {"history": clipboard_history}
6.3 跨设备通知
使用WebSocket实现实时通知:
python复制from fastapi import WebSocket
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
while True:
data = await websocket.receive_text()
await websocket.send_text(f"Message received: {data}")
7. 常见问题排查
7.1 无法访问服务
- 检查防火墙设置,确保8000端口开放
- 确认设备在同一局域网下
- 尝试使用电脑IP地址而非localhost访问
7.2 文件上传失败
- 检查
python-multipart是否安装 - 确保上传目录有写入权限
- 检查磁盘空间是否充足
7.3 剪贴板不同步
- 检查前端是否正确发送了JSON数据
- 确认没有浏览器插件拦截了请求
- 查看浏览器控制台是否有错误信息
这个工具虽然简单,但确实解决了我日常工作中的很多痛点。现在我在办公室和家里都常驻这个服务,手机和电脑之间的文件传输再也不是问题。最让我惊喜的是剪贴板同步功能,现在写代码时看到手机上的错误信息,直接复制就能在电脑上搜索,效率提升非常明显。
