一、优化文件传输功能:从上传到下载的闭环
在上一篇教程中,我们实现了基础的文件上传功能,但一个完整的文件共享工具还需要支持文件下载。接下来我们为工具添加文件下载和文件列表展示功能,让局域网内的设备可以自由获取共享文件。
首先,我们需要添加一个接口来获取服务器上的文件列表:
from fastapi.responses import FileResponse
@app.get("/file-list/")
async def get_file_list():
files = []
for filename in os.listdir(UPLOAD_DIR):
file_path = os.path.join(UPLOAD_DIR, filename)
if os.path.isfile(file_path):
files.append({
"filename": filename,
"size": os.path.getsize(file_path),
"download_url": f"/download/{filename}"
})
return {"files": files}
这个接口会遍历上传目录,返回所有文件的名称、大小和下载链接,方便用户查看和选择需要下载的文件。
然后添加文件下载接口:
@app.get("/download/{filename}")
async def download_file(filename: str):
file_path = os.path.join(UPLOAD_DIR, filename)
if not os.path.exists(file_path) or not os.path.isfile(file_path):
return {"error": "文件不存在"}
return FileResponse(file_path, filename=filename)
通过FileResponse,FastAPI可以直接将文件发送给客户端,实现一键下载功能。
二、增强剪贴板功能:多设备同步与历史记录
基础的剪贴板同步功能只能保存一条内容,我们可以进一步优化,添加剪贴板历史记录和多设备同步支持。
首先修改剪贴板存储结构,使用列表来保存历史记录:
clipboard_history = []
MAX_HISTORY = 10 # 最多保存10条历史记录
然后更新设置剪贴板的接口,将新内容添加到历史记录中,并保持记录数量不超过最大值:
@app.post("/set-clipboard/")
async def set_clipboard(content: str = Form(...)):
# 添加新内容到历史记录开头
clipboard_history.insert(0, {"content": content, "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")})
# 保持历史记录数量不超过最大值
if len(clipboard_history) > MAX_HISTORY:
clipboard_history.pop()
return {"message": "剪贴板内容已更新", "content": content}
同时添加一个接口来获取剪贴板历史记录:
@app.get("/clipboard-history/")
async def get_clipboard_history():
return {"history": clipboard_history}
这样用户就可以查看之前复制的内容,方便在不同设备间切换使用。
三、提升用户体验:添加进度显示与错误处理
为了让工具更加易用,我们需要添加一些用户体验优化。首先更新网页界面,添加文件列表展示和剪贴板历史记录查看功能:
@app.get("/", response_class=HTMLResponse)
async def main_page():
# 获取文件列表
files = []
for filename in os.listdir(UPLOAD_DIR):
file_path = os.path.join(UPLOAD_DIR, filename)
if os.path.isfile(file_path):
files.append(filename)
# 获取剪贴板历史记录
history = clipboard_history[:5] # 只显示最近5条记录
return f"""
<html>
<body>
<h1>局域网文件+剪贴板工具</h1>
<h2>文件上传</h2>
<form action="/upload-file/" enctype="multipart/form-data" method="post">
<input name="file" type="file" multiple>
<input type="submit" value="上传文件">
</form>
<h2>文件列表</h2>
<ul>
{''.join([f'<li><a href="/download/{file}">{file}</li>' for file in files])}
</ul>
<h2>剪贴板同步</h2>
<form action="/set-clipboard/" method="post">
<textarea name="content" rows="4" cols="50" placeholder="输入剪贴板内容"></textarea>
<br>
<input type="submit" value="设置剪贴板">
</form>
<h3>最近剪贴板记录</h3>
<ul>
{''.join([f'<li>{item["content"]} - {item["timestamp"]}</li>' for item in history])}
</ul>
<a href="/clipboard-history/">查看完整历史记录</a>
</body>
</html>
"""
这个界面会动态显示文件列表和最近的剪贴板记录,让用户可以直观地管理文件和查看剪贴板历史。
另外,我们还需要添加错误处理机制,比如当用户上传过大文件或不支持的文件类型时,给出友好的提示:
@app.post("/upload-file/")
async def create_upload_file(file: UploadFile = File(...)):
# 限制文件大小不超过100MB
MAX_FILE_SIZE = 100 * 1024 * 1024 # 100MB
file.file.seek(0, os.SEEK_END)
file_size = file.file.tell()
file.file.seek(0)
if file_size > MAX_FILE_SIZE:
return {"error": "文件大小超过限制(最大100MB)"}
# 限制文件类型
ALLOWED_EXTENSIONS = {"txt", "pdf", "png", "jpg", "jpeg", "gif", "doc", "docx", "xls", "xlsx"}
if not file.filename.split(".")[-1].lower() in ALLOWED_EXTENSIONS:
return {"error": "不支持的文件类型"}
file_path = os.path.join(UPLOAD_DIR, file.filename)
with open(file_path, "wb") as buffer:
shutil.copyfileobj(file.file, buffer)
return {"filename": file.filename, "message": "文件上传成功", "save_path": file_path}
通过这些优化,我们的局域网文件剪贴板工具变得更加实用和稳定。
四、部署与使用:让工具真正用起来
为了让工具在局域网内更加易用,我们可以做一些部署优化:
设置固定端口和自动启动:修改启动命令为
uvicorn main:app --host 0.0.0.0 --port 8000 --reload,其中--reload参数会在代码修改时自动重启服务,方便开发调试。创建快捷启动脚本:在Windows系统中,可以创建一个批处理文件
start.bat,内容为:
@echo off
cd /d "脚本所在目录"
uvicorn main:app --host 0.0.0.0 --port 8000
双击即可启动服务。
获取局域网IP地址:在命令行中输入
ipconfig(Windows)或ifconfig(Mac/Linux),找到局域网IP地址,比如192.168.1.100,其他设备通过访问http://192.168.1.100:8000即可使用工具。
现在,你已经拥有了一个功能完善的局域网文件剪贴板工具,无论是手机传文件到电脑,还是电脑传文件到平板,甚至是多设备间的剪贴板同步,都可以轻松实现,彻底摆脱数据线的束缚!