使用flask构建一个简单的文件同步系统

ops/2024/10/25 6:59:09/

使用Python构建文件同步系统:步骤指南

在当今互联网时代,能够在本地机器和远程服务器之间同步文件的能力变得至关重要。无论是备份重要文档、与团队成员共享大文件,还是在多个设备间保持数据一致性,一个强大的文件同步系统都能发挥重要作用。在这篇博客文章中,我们将逐步介绍如何使用Python构建一个简单而强大的文件同步系统,并为大文件传输添加进度条功能。

挑战

我们的目标是创建一个系统,能够:

  1. 将本地文件上传到远程服务器
  2. 从服务器下载文件到本地机器
  3. 检查服务器上是否存在某个文件
  4. 处理大文件传输并提供可视化反馈

解决方案

我们将分两部分构建我们的解决方案:一个使用Flask的服务器端应用程序,和一个与服务器交互的客户端脚本。

第一部分:服务器

首先,让我们使用Flask创建一个简单的服务器,它可以处理文件上传、下载和存在性检查。

python">from flask import Flask, request, send_file, jsonify
import osapp = Flask(__name__)
UPLOAD_FOLDER = 'uploads'
if not os.path.exists(UPLOAD_FOLDER):os.makedirs(UPLOAD_FOLDER)@app.route('/upload', methods=['POST'])
def upload_file():if 'file' not in request.files:return jsonify({"error": "没有文件部分"}), 400file = request.files['file']if file.filename == '':return jsonify({"error": "没有选择文件"}), 400if file:filename = os.path.join(UPLOAD_FOLDER, file.filename)file.save(filename)return jsonify({"message": "文件上传成功"}), 200@app.route('/download/<filename>', methods=['GET'])
def download_file(filename):filepath = os.path.join(UPLOAD_FOLDER, filename)if os.path.exists(filepath):return send_file(filepath, as_attachment=True)else:return jsonify({"error": "文件未找到"}), 404@app.route('/check/<filename>', methods=['GET'])
def check_file(filename):filepath = os.path.join(UPLOAD_FOLDER, filename)if os.path.exists(filepath):return jsonify({"exists": True}), 200else:return jsonify({"exists": False}), 200if __name__ == '__main__':app.run(host='0.0.0.0', port=5000)

这个服务器提供了三个主要端点:

  • /upload 用于文件上传
  • /download/<filename> 用于文件下载
  • /check/<filename> 用于检查服务器上是否存在某个文件

第二部分:客户端

现在,让我们创建一个客户端脚本,它可以与我们的服务器交互并处理文件同步。我们将使用 requests 库进行HTTP通信,使用 tqdm 库来显示进度条。

python">import requests
import os
from tqdm import tqdmSERVER_URL = "http://your_server_ip:5000"def upload_file(filename):file_size = os.path.getsize(filename)with open(filename, 'rb') as f:with tqdm(total=file_size, unit='B', unit_scale=True, desc=f"正在上传 {filename}") as pbar:response = requests.post(f"{SERVER_URL}/upload",files={"file": f},data={"filename": os.path.basename(filename)},headers={"Content-Length": str(file_size)},stream=True)for chunk in response.iter_content(chunk_size=8192):if chunk:pbar.update(len(chunk))print(response.json())def download_file(filename):with requests.get(f"{SERVER_URL}/download/{filename}", stream=True) as response:if response.status_code == 200:total_size = int(response.headers.get('content-length', 0))with open(filename, 'wb') as f, tqdm(total=total_size, unit='B', unit_scale=True, desc=f"正在下载 {filename}") as pbar:for chunk in response.iter_content(chunk_size=8192):if chunk:size = f.write(chunk)pbar.update(size)print(f"文件 {filename} 下载成功")else:print(response.json())def check_file(filename):response = requests.get(f"{SERVER_URL}/check/{filename}")return response.json()['exists']def sync_file(filename):if os.path.exists(filename) and not check_file(filename):print(f"正在将 {filename} 上传到服务器...")upload_file(filename)elif check_file(filename) and not os.path.exists(filename):print(f"正在从服务器下载 {filename}...")download_file(filename)elif not check_file(filename) and not os.path.exists(filename):print(f"文件 {filename} 在本地和服务器上都不存在")else:print(f"文件 {filename} 在本地和服务器上都已存在")# 使用示例
sync_file("large_file.zip")

这个客户端脚本提供了几个关键功能:

  1. 文件上传:将文件发送到服务器,并显示进度条。
  2. 文件下载:从服务器检索文件,并显示进度条。
  3. 文件检查:验证服务器上是否存在某个文件。
  4. 同步逻辑:根据文件在本地和服务器上的存在情况,决定是上传、下载还是跳过该文件。

sync_file 函数封装了我们的同步逻辑:

  • 如果文件在本地存在但服务器上不存在,则上传。
  • 如果文件在服务器上存在但本地不存在,则下载。
  • 如果文件在两个位置都不存在,我们会得到通知。
  • 如果文件在两个位置都存在,我们会得到通知,无需采取任何操作。

整合使用

要使用这个文件同步系统:

  1. 在您的远程机器上启动Flask服务器。
  2. 在客户端脚本中更新 SERVER_URL,使其指向您的服务器。
  3. 运行客户端脚本,指定您想要同步的文件。

此外,如果你是本地服务器,进行了内网穿透,可以使用以下代码,优先使用本地ip地址,下面代码做了优化,将函数封装成为一个类

python">import requests
import os
from tqdm import tqdm
import timeclass FileSync:def __init__(self, server_url1, server_url2):self.SERVER_URL1 = server_url1self.SERVER_URL2 = server_url2self.server_url = Nonedef check_server(self, url):try:response = requests.get(url, timeout=5)return response.status_code == 200except requests.RequestException:return Falsedef get_server_url(self):if self.check_server(self.SERVER_URL1 + "check/test.txt"):self.server_url = self.SERVER_URL1return self.SERVER_URL1elif self.check_server(self.SERVER_URL2 + "check/test.txt"):self.server_url = self.SERVER_URL2return self.SERVER_URL2else:raise Exception("无法连接到任何服务器")def upload_file(self, filename):self.get_server_url()file_size = os.path.getsize(filename)with open(filename, 'rb') as f:with tqdm(total=file_size, unit='B', unit_scale=True, desc=f"正在上传 {filename}") as pbar:response = requests.post(f"{self.server_url}upload",files={"file": (os.path.basename(filename), f)},data={"filename": os.path.basename(filename)},stream=True)for chunk in iter(lambda: f.read(8192), b''):if chunk:pbar.update(len(chunk))print(response.json())def download_file(self, filename):self.get_server_url()with requests.get(f"{self.server_url}download/{os.path.basename(filename)}", stream=True) as response:if response.status_code == 200:total_size = int(response.headers.get('content-length', 0))block_size = 8192with open(filename, 'wb') as f, tqdm(total=total_size, unit='B', unit_scale=True, desc=f"正在下载 {filename}") as pbar:for chunk in response.iter_content(block_size):size = f.write(chunk)pbar.update(size)print(f"文件 {filename} 下载成功")else:print(response.json())def check_file(self, filename):self.get_server_url()basename = os.path.basename(filename)response = requests.get(f"{self.server_url}check/{basename}")return response.json()['exists']def sync_file(self, filename):try:self.get_server_url()  # 确保使用可用的服务器basename = os.path.basename(filename)if os.path.exists(filename) and not self.check_file(basename):print(f"正在将 {filename} 上传到服务器...")self.upload_file(filename)elif self.check_file(basename) and not os.path.exists(filename):print(f"正在从服务器下载 {filename}...")self.download_file(filename)elif not self.check_file(basename) and not os.path.exists(filename):print(f"文件 {filename} 在本地和服务器上都不存在")else:print(f"文件 {filename} 在本地和服务器上都已存在")except Exception as e:print(f"同步过程中发生错误: {str(e)}")# 使用示例
if __name__ == "__main__":sync = FileSync("http://你弟内网ip/:5000", "http://你的公网ip:5000")# print(sync.check_file("test.txt"))sync.sync_file(r"C:\BaiduSyncdisk\code&note\0A-ZATA\data\光谱数据\MZI酒精数据_21&27&79&30_.xlsx")

结论

这个简单而有效的文件同步系统展示了我们如何利用Python创建强大的工具来管理不同位置的数据。添加进度条使其特别适用于处理大文件,在可能较长的传输操作期间提供视觉反馈。

虽然这个系统是一个很好的起点,但还有许多方式可以扩展它:

  • 添加身份验证以实现安全的文件传输
  • 实现文件版本控制
  • 创建监视系统,自动同步更改
  • 开发图形用户界面,便于交互

祝您编码愉快,愿您的文件永远保持同步!


http://www.ppmy.cn/ops/128262.html

相关文章

Docker加载并运行别人的容器的同时挂在本地其他文件

配置环境失败后迫不得已入坑docker 踩坑1.sudo docker start hunyuandit_new Error response from daemon: could not select device driver "" with capabilities: [[gpu]] Error: failed to start containers: hunyuandit_new 解决方法&#xff1a; 安装Install…

PyQt 入门教程(3)基础知识 | 3.1、使用QtDesigner创建.ui文件

文章目录 一、使用QtDesigner创建.ui文件1、创建.ui文件2、生成.py文件3、使用新生成的.py文件4、编辑新生成的.py文件 一、使用QtDesigner创建.ui文件 1、创建.ui文件 打开PyCharm&#xff0c;使用自定义外部工具QtDesigner创建mydialog.ui文件&#xff0c;如下&#xff1a; …

植物健康,Spring Boot来保障

5系统详细实现 5.1 系统首页 植物健康系统需要登录才可以看到首页。具体界面的展示如图5.1所示。 图5.1 系统首页界面 5.2 咨询专家 可以在咨询专家栏目发布消息。具体界面如图5.2所示。 图5.2 咨询专家界面 5.3 普通植物检查登记 普通员工可以对普通植物检查登记信息进行添…

【深度学习代码调试5】标准化数据集:TensorFlow Datasets (TFDS)自动化数据加载与预处理

【标准化数据集】TensorFlow Datasets、TFDS&#xff1a;自动化数据加载与预处理 写在最前面1. 什么是 TensorFlow Datasets (TFDS)?主要特点&#xff1a; 2. TFDS 的核心 API&#xff1a;tfds.builder 和 download_and_preparetfds.builder&#xff1a;创建数据集构建器示例&…

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-18

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-18 目录 文章目录 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-18目录1. On the Reliability of Large Language Models to Misinformed and Demographically-Informed Prompts2. SafeLLM: Dom…

限流是什么?如何限流?怎么限流?

概述 什么是限流 对某一时间窗口内的请求数进行限制,保持系统的可用性和稳定性,防止因流量暴增而导致的系统运行缓慢或宕机 为什么要限流 因为互联网系统通常都要面对大并发大流量的请求,在突发情况下(最常见的场景就是秒杀、抢购),瞬时大流量会直接将系统打垮,无法…

【硬件篇】k8s云原生开发要求

k8s云原生开发对硬件有一定要求。CPU方面&#xff0c;建议至少配备2个逻辑核心&#xff0c;高性能CPU更佳。内存至少4GB&#xff0c;但8GB或更高更推荐。存储需至少20-30GB可用空间&#xff0c;SSD提升IO性能。网络要求稳定&#xff0c;建议使用私有网络VPC&#xff0c;并配置与…

java-实例化一个List,然后添加数据的方法详解

在Java中&#xff0c;实例化一个 List 并向其中添加数据非常简单。List 是一个接口&#xff0c;因此我们通常使用它的常见实现类 ArrayList 或 LinkedList。以下是一些常见的操作方法&#xff1a; ### 1. 使用 ArrayList 实例化并添加数据 java import java.util.ArrayList; …