python+Java的网盘程序升级版。无感知备份文档,保护数据资产利器。

之前的版本,经过使用中测试,发现让普通使用者设置备份路径,可能有点难度。特增加了默认设置,直接读取电脑所有盘符,监控所有文件的创建和修改记录,实时备份。还增加了特殊路径忽略配置,因为有些软件生成的文件是无需备份要排除干扰的。另外还特地增加了非第三方在线编辑功能。总体功能跟新如下:

1、实时监控指定目录,或所有盘符的文件变化信息,新增、修改、删除。

2、多线程文件传输。

3、大文件分片传输,然后在服务器端自动合成。(试验了传输单个60G大文件压缩包,服务器端合成后,可正常打开)

4、一次性传输目录下所有文件。用于初始化监控时同步全部文件。

5、用户验证。(访问web接口验证用户权限)

6、文件历史版本保存。(还在考虑需不需要,需要时再做吧,升级服务器端代码就行了)

7、程序启动时,自动最小化到系统盘图标。

8、增加配置:忽略路径、忽略文件类型、只传文件类型。

9、配置文件分:个人配置,和统一配置,统一配置由服务器端获取,实现个性化监控。

10、在线编辑功能:在浏览器端查看office文件时,点击文件名可直接打开文件编辑,保存后自动上传。

这里记录一下此次重要升级,在线编辑功能的实现办法。没有考虑使用第三方的原因是,需要安装编辑服务器,这个可以后续再对接onlyoffice。我的网盘在线编辑是直接调用本地office软件进行文件编辑,原汁原味,体验更好,保存后无感知自动上传。

实现思路是在网盘python客户端实现一个web服务,接受URL传参触发文件路径比对,如果本地同路径文件存在,则直接调用office打开编辑,如果本地文件不存在,则下载保存到本地同途径,再打开编辑。保持了网络文件与本地文件一致。

WEB服务代码:

引用URL检测代码模块:

from webSrv import DocumentHandler

监控URL中的get请求。

webSrv.py详细代码:

from http.server import HTTPServer, BaseHTTPRequestHandler import json import os import base64 import configparser import requests import time from urllib.parse import unquote from urllib.parse import unquote_plus import tkinter as tk from tkinter import messagebox import subprocess # 全局变量存储文档数据 documents = [ {"id": 1, "title": "项目计划书", "content": "这是项目计划书的内容..."}, {"id": 2, "title": "技术规范文档", "content": "这里是技术规范说明..."}, {"id": 3, "title": "用户手册", "content": "用户手册详细操作指南..."} ] class DocumentHandler(BaseHTTPRequestHandler): def do_GET(self): #root.after(100 , log_message(f"11111111111111", "info")) if self.path == '/mydocuments': self.send_response(200) self.send_header('Content-type', 'application/json') self.send_header('Access-Control-Allow-Origin', '*') self.end_headers() # 返回文档列表 self.wfile.write(json.dumps(documents, ensure_ascii=False).encode('utf-8')) #self.wfile.close() # 关闭连接 #self.rfile.close() # 关闭连接 elif self.path.startswith('/mydocuments/'): try: doc_id = int(self.path.split('/')[-1]) doc = next((d for d in documents if d["id"] == doc_id), None) if doc: self.send_response(200) self.send_header('Content-type', 'application/json') self.send_header('Access-Control-Allow-Origin', '*') self.end_headers() self.wfile.write(json.dumps(doc, ensure_ascii=False).encode('utf-8')) else: self.send_error(404, "Document not found") except ValueError: self.send_error(400, "Invalid document ID") elif self.path.startswith('/openfile/?'): #在非控制台模式下响应异常,尝试将send_response替换为send_response_only #self.send_response(200) self.send_response_only(200) self.send_header('Content-type', 'text/html') self.send_header('Access-Control-Allow-Origin', '*') self.end_headers() docUrl = self.path.split('?')[1] docUid = docUrl.split('***')[0] #参数传过来的当前uid,可能不是GUI登录的UID docPath = docUrl.split('***')[1] # 发送响应体 message = "<html><body><h1>" + docUid + " OpenFile:"+docPath+"</h1></body></html>" self.wfile.write(message.encode('utf-8')) guiuid = self.getUserCfg("userid") if docUid == guiuid: self.toOpenFile(docPath) else: self.showmsg(400,80,"电脑端备份软件登录的用户不是:"+docUid) return else: self.send_error(404, "Path not found") def do_POST(self): if self.path == '/mydocuments': content_length = int(self.headers['Content-Length']) post_data = self.rfile.read(content_length) try: new_doc = json.loads(post_data.decode('utf-8')) new_doc["id"] = max([d["id"] for d in documents], default=0) + 1 documents.append(new_doc) self.send_response(201) self.send_header('Content-type', 'application/json') self.send_header('Access-Control-Allow-Origin', '*') self.end_headers() self.wfile.write(json.dumps(new_doc, ensure_ascii=False).encode('utf-8')) except json.JSONDecodeError: self.send_error(400, "Invalid JSON") else: self.send_error(404, "Path not found") def do_OPTIONS(self): self.send_response(200) self.send_header('Access-Control-Allow-Origin', '*') self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS') self.send_header('Access-Control-Allow-Headers', 'Content-Type') self.end_headers() def showmsg(self,wid,hig,msgx): # 创建主窗口 root = tk.Tk() root.title("提示") root.resizable(False, False) width = wid height= hig screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() x = (screen_width - width) // 2 y = (screen_height - height) // 2 root.geometry(f"{width}x{height}+{x}+{y}") #root.geometry("600x100") # 设置窗口大小,根据需要调整 root.attributes('-topmost', True) # 确保窗口在最顶层 # 创建一个标签显示消息 label = tk.Label(root, text=msgx, font=('Arial', 12), wraplength=500) label.pack(pady=20) # 在窗口中居中显示消息 # 设置3秒后关闭窗口 root.after(3000, root.destroy) # 3000毫秒后调用root.destroy()方法关闭窗口 #root.protocol("WM_DELETE_WINDOW", lambda: None) # 禁止通过点击关闭按钮关闭窗口 # 进入主事件循环 root.mainloop() #file_path=/我的E盘/temp/测试.docx def toOpenFile(self , file_path): file_path = unquote_plus(file_path) file_path = file_path.replace("\\","/") file_path = file_path.replace("//","/") file_path = file_path.replace("//","/") file_path = file_path.replace("//","/") print("网盘路径:"+file_path) locPath = self.getLocatPath(file_path) print("本地路径:"+locPath) #file_path = 'example.txt' if len(locPath)<1: self.showmsg(300,80,"本地此文件夹配置不存在") return if len(locPath) > 1 and file_path[-1]=="/": #如果是/结尾的,表示打开本地目录 if os.path.exists(locPath): self.showmsg(300,80,"打开本地文件夹中......") subprocess.Popen(['start', '', '/max', locPath], shell=True) else: self.showmsg(300,80,"本地此文件夹不存在") return if len(locPath) > 1 and os.path.exists(locPath): self.showmsg(300,80,"打开文件中......") subprocess.Popen(['start', '', '/max', locPath], shell=True) #os.startfile(locPath) else: print(">>>notfile>>>"+locPath) self.showmsg(600,80,"本地对应文件不存在:"+locPath + ",开始下载打开编辑。") self.down_file(file_path , locPath) if os.path.exists(locPath): subprocess.Popen(['start', '', '/max', locPath], shell=True) def getUserCfg(self , keyy): config = configparser.ConfigParser() config.read('config_user.ini' , encoding='utf-8') return config.get('main', keyy).strip() #入参file_path格式 #/我的C盘/1222/11111/1111/2222.doc def getLocatPath(self,file_path): locd = "" file_path = unquote_plus(file_path) if file_path.count("/") == 1: #如果是网盘根目录下的文件 os.makedirs("c:/deskDoc", exist_ok=True) return "c:/deskDoc" + file_path rfod = file_path.split('/')[1] config = configparser.ConfigParser() config.read('config_user.ini' , encoding='utf-8') loc = config.get('main', 'locdir').strip() # c:/ rmt = config.get('main', 'rmtdir').strip() if rfod.lower().strip() == rmt.lower().strip(): locd = loc + file_path[len(rmt)+1:len(file_path)] else: self.json_file = "path_config.json" if os.path.exists(self.json_file): with open(self.json_file, "r", encoding="utf-8") as f: datas = json.load(f) self.path_cfg = datas for item_data in datas: phh = item_data.get('local_path') rhh = item_data.get('remote_directory') if rfod.lower().strip() == rhh.lower().strip(): locd = phh + file_path[len(rhh)+1:len(file_path)] locd = locd.replace("\\","/") locd = locd.replace("//","/") return locd #入参url格式 #/我的C盘/1222/11111/1111/2222.doc def down_file(self , url , savedir): url = unquote_plus(url) savedir = unquote_plus(savedir) #读取个人设置 config = configparser.ConfigParser() config.read('config_user.ini' , encoding='utf-8') uid = config.get('main', 'userid').strip() # c:/ pwd = config.get('main', 'password').strip() try: pwd = base64.b64decode(pwd).decode() #密码解密 except Exception as e: pwd = "" #读取服务器配置 configs = configparser.ConfigParser() configs.read('config_srv.ini' , encoding='utf-8') self.conf_srv_ip = configs.get('main', 'srv_ip') self.conf_srv_pt = configs.get('main', 'srv_port') self.conf_srv_ur = configs.get('main', 'srv_url') self.conf_srv_ls = configs.get('main', 'srv_list') s = url.rfind("/") #相当于lastindexof fodd = url[:s] fnam = url[s:] fnam = fnam.replace("/","") durl = self.conf_srv_ip + ":" + self.conf_srv_pt + "/" + self.conf_srv_ls + "/downx.jsp?" durl = durl + "file=" + fodd + "&" durl = durl + "name=" + fnam + "" durl = durl.replace("\\","/") durl = durl.replace("//","/") savedir = savedir.replace("\\","/") savedir = savedir.replace("//","/") print("【down url】"+durl) s = savedir.rfind("/") sdir = savedir[:s] self.download_file(durl , sdir , fnam , uid , pwd) def download_file(self, url, save_dir=None,file_name=None,uid=None,pwd=None): """ 下载文件并保存到指定路径,从网络路径中query参数中获取文件名,例如https://127.0.0.1:8000/web/file?path=2025041616372016\\5ed63734774b40d181fd96e1c58133d2.pdf :param url: 文件下载URL :param save_dir: 文件保存路径 :param file_name: 文件名 """ headers = { 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7;application/json, text/javascript, */*; q=0.01', 'Accept-Encoding': 'gzip, deflate, br', 'Accept-Language': 'zh-CN,zh;q=0.9', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'Cookie': '132213213213213213', 'x-username': f'{uid}', 'x-userpwd': f'{pwd}', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36' } try: if file_name is None: print("not file_name") return False if save_dir is None: print("not save_dir") return False save_path = os.path.abspath(save_dir) file_path = os.path.join(save_path, file_name) if save_dir and not os.path.exists(save_dir): os.makedirs(save_dir, exist_ok=True) response = requests.get("http://"+url, stream=True, headers=headers) response.raise_for_status() with open(file_path, 'wb') as file: file.write(response.content) return True except requests.exceptions.RequestException as e: print(f"网络请求失败:{str(e)}") except IOError as e: print(f"文件操作失败:{str(e)}") except Exception as e: print(f"未知错误:{str(e)}") return False

经过这段时间研究,越来越喜欢python了。生态强大资源丰富。在微服务应用上大有可为哦。

在线编辑office文件触发效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1164512.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

人工智能-AI下游应用端核心赛道(教育/医疗/金融)个股对比表【20260115】

文章目录 AI下游应用端核心赛道(教育/医疗/金融)个股对比表 一、AI+教育赛道:因材施教,政策驱动规模化落地 二、AI+医疗赛道:效率革命,刚需驱动商业化加速 三、AI+金融赛道:风控为王,技术驱动效率提升 四、三大赛道核心投资逻辑与筛选指南 总结 AI下游应用端核心赛道(…

红外图像水管管道破裂漏水检测数据集VOC+YOLO格式93张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件)图片数量(jpg文件个数)&#xff1a;93标注数量(xml文件个数)&#xff1a;93标注数量(txt文件个数)&#xff1a;93标注类别数&…

无人机航拍黑匣子目标检测数据集_91张高清图像_907个精确标注_适用于计算机视觉模型训练与评估

无人机航拍黑匣子目标检测数据集分析报告 引言与背景 随着计算机视觉技术的快速发展&#xff0c;目标检测在各个领域的应用日益广泛&#xff0c;特别是在航拍图像分析方面具有重要价值。无人机航拍视角独特&#xff0c;能够从高空俯瞰地面场景&#xff0c;为目标监测、资源调…

sward快速上手教程,从安装到入门

sward&#xff0c;一款国产开源的知识管理工具&#xff0c;包含知识库管理、文档管理、文档审批、文档共享等模块&#xff0c;支持富文本文档、markdown等格式&#xff0c;产品简洁易用、开源免费&#xff0c;本文将介绍如何安装及快速入门。 1、安装 sward支持多系统安装&am…

演示开挂!宏智树 AI AIPPT 功能让学术办公 PPT 一键封神

作为深耕论文写作科普的教育博主&#xff0c;后台总能刷到这样的求助&#xff1a;“开题报告 PPT 逻辑乱成麻&#xff0c;被导师批得一无是处”“论文答辩 PPT 数据堆砌&#xff0c;评委全程皱眉头”“工作汇报 PPT 设计土气&#xff0c;汇报效果大打折扣”。制作一份优质 PPT&…

Python深拷贝与浅拷贝数据讲解:理解对象复制的核心机制

在Python编程中&#xff0c;对象复制是一个常见但容易出错的操作。许多开发者在处理可变对象&#xff08;如列表、字典&#xff09;时&#xff0c;常常会遇到"修改副本却影响了原对象"的困惑。这背后正是深拷贝和浅拷贝机制在起作用。本文将系统讲解这两种拷贝方式的…

科普课堂|宏智树 AI:手把手带教,毕业论文写作通关秘籍

作为深耕论文写作科普的教育博主&#xff0c;后台每天都被毕业生的求助填满&#xff1a;“选题太宽泛&#xff0c;导师说没研究价值怎么办&#xff1f;”“文献看了上百篇&#xff0c;综述还是写成了流水账&#xff1f;”“数据堆了一堆&#xff0c;不知道怎么分析才够硬核&…

AI提示词(Prompt)入门:什么是Prompt?为什么要写好Prompt?

AI提示词&#xff08;Prompt&#xff09;入门&#xff1a;什么是Prompt&#xff1f;为什么要写好Prompt&#xff1f; 在AI技术飞速迭代的今天&#xff0c;大语言模型已成为工作生活中的常用工具——写方案、改文案、查资料、做分析&#xff0c;只需输入一段文字&#xff0c;AI就…

Qt 小技巧:如何用 Q_PROPERTY 管理属性

在 Qt 开发中&#xff0c;属性是对象的重要组成部分。尤其是在与 UI 交互时&#xff0c;如何高效、清晰地管理属性就显得尤为重要。今天&#xff0c;我们将深入探讨 Qt 中的 Q_PROPERTY 宏&#xff0c;它是如何帮助我们简化属性的声明、管理与使用的。如果你曾经在 Qt 中编写过…

kanass实践教程 - 如何使用kanass高效的管理项目

kanass是一款简洁易用的项目管理工具&#xff0c;它为项目经理管理项目提供了更丰富、更简单的管理方式&#xff0c;本篇文章主要介绍项目经理如何通过kanass来管理项目。1、创建项目点击项目->添加项目->选择项目模板系统提供多种项目模版&#xff0c;如敏捷式项目、瀑布…

Java毕设项目:基于SpringBoot+vue的社区旧衣物回收与捐赠系统设计与实现基于SpringBoot的社区旧衣物回收与捐赠系统设计与实现(源码+文档,讲解、调试运行,定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

2026年节假日表SQL

2025节假日表 drop TABLE calendar_holiday; CREATE TABLE calendar_holiday (date DATE PRIMARY KEY,year INT NOT NULL,month INT NOT NULL,day INT NOT NULL,weekday_name VARCHAR(10) NOT NULL, -- 星期一 ~ 星期日is_weekend TINYINT DEFAULT 0, -- 是否为周末 (0:否…

灵魂拷问:你写的测试代码比AI生成的更优雅吗?

优雅测试代码的定义与行业背景 在软件测试领域&#xff0c;“优雅”的测试代码不仅关乎功能正确性&#xff0c;更强调可读性、简洁性、可维护性和高效性——它像一首精炼的诗&#xff0c;让后续维护者一目了然。随着AI工具&#xff08;如GitHub Copilot、Testim&#xff09;的…

基于深度学习的安全帽检测系统(YOLOv8+YOLO数据集+UI界面+Python项目+模型)

一、项目介绍 摘要 本项目基于YOLOv8&#xff08;You Only Look Once v8&#xff09;目标检测算法&#xff0c;开发了一套高效、精准的安全帽佩戴检测系统&#xff0c;主要用于监控建筑工地、工厂、电力设施等高危作业环境&#xff0c;确保工作人员正确佩戴安全帽&#xff0c…

基于深度学习的水果检测系统(YOLOv8+YOLO数据集+UI界面+Python项目+模型)

一、项目介绍 摘要 本项目基于YOLOv8&#xff08;You Only Look Once version 8&#xff09;深度学习目标检测算法&#xff0c;开发了一套高效精准的水果自动检测与识别系统。系统能够智能识别6类常见水果&#xff1a;苹果&#xff08;Apple&#xff09;、香蕉&#xff08;Ba…

开题报告通关秘籍!宏智树 AI 教你三步搞定学术蓝图

作为深耕论文写作科普的教育博主&#xff0c;后台每天都被 “开题报告改了 N 遍还被毙” 的求助淹没。选题太泛没焦点、文献综述像流水账、技术路线混乱不清…… 这些问题堪称学术萌新的 “开题噩梦”。其实&#xff0c;一份合格的开题报告&#xff0c;本质是向导师证明 “你的…

软考-系统架构师-未来信息综合技术(二)

四、机器人技术 4.1、机器人的定义与构成 4.1.1、定义条件 具有如下3个条件的机器可以称为机器人&#xff1a; 1&#xff09;具有脑、手、脚等三要素的个体&#xff1b; 2&#xff09;具有非接触传感器&#xff08;用眼、耳接收远方信息&#xff09;和接触传感器&#xff1b; 3…

数据 “活” 起来!宏智树 AI 解锁论文数据分析零门槛通关秘籍

作为深耕论文写作科普的教育博主&#xff0c;后台总能收到这样的灵魂吐槽&#xff1a;“问卷数据收了 300 份&#xff0c;对着 SPSS 界面两眼发黑”“实验数据一堆&#xff0c;却不知道怎么分析才能支撑论点”“好不容易做出图表&#xff0c;被导师批‘不专业、没逻辑’”。论文…

Spring AI实战:实现流式对话中的会话终止功能

前言在AI对话系统中&#xff0c;流式响应&#xff08;Streaming&#xff09;已成为提升用户体验的重要技术。然而&#xff0c;当用户面对长时间生成的回复时&#xff0c;往往希望能够在中途终止对话。本文将详细介绍如何在基于Spring AI的项目中实现流式对话的会话终止功能&…

AI质检驱动质量革命:从被动救火到主动免疫的体系重构

——星云科技智能测试中台三年演进实录一、故障归零目标的残酷现实挑战传统测试的效能天花板微服务架构下每月超2万次版本发布人工回归测试覆盖率长期徘徊在35%-42%2023年Q3生产环境P1级故障27次&#xff0c;平均修复耗时6.2小时质量防控的四大盲区graph LR A[流量突变场景] --…