新闻详情

新闻详情

首页 / 资讯中心 / 详情

在手机上运行Python增量备份手机数据到PC电脑

发布时间:2026/9/28 4:46:21来源:尧图网络
在手机上运行Python增量备份手机数据到PC电脑
一、需求背景最近备份手机数据直连电脑然后把手机上的照片全都拷出来却遇到了几个问题直连 USB线是2.0速度手机上100个GB的照片视频文件拷贝花了一整个晚上。在手机上删照片在30日内还可以还原实际上实现的原理是将这个照片文件换了一个文件名将它标记为隐藏了然而直连数据线将文件夹拷贝出来会将这些文件也拷出来。不仅是已删除的文件还有 .thumbnail 开头的缩略图文件、各种隐藏文件全都会被拷贝出来这些是不需要的。文件夹里有一些压缩包、文档等非媒体文件也一并拷出来了这些也是我不需要的。我手机上的数据隔几个月就会备份一次但是数据大部分是已经备份过的所以每次拷贝都拷出来100GB的文件实在是太浪费了既浪费时间、也浪费电脑的空间。使用NAS也许可以解决这样的问题但是我不想使NAS我也不想花钱买云服务NAS通常可以同步「新增」但是不能同步「修改」和「删除」我希望更高颗粒度地备份手机文件数据二、解决方案我在手机和电脑上分别写了一个跨网络传输脚本可以在拷贝文件的时候跳过隐藏文件夹、跳过PC上已存在的文件、保持文件夹结构、还原手机上文件的修改最后时间。2.1 首先是一个公用的 util.py 模块对TCP服务进行包装简易调用写了一个File类可以惰性获取文件的大小、MD5值、文件最后修改时间。当判断文件的文件名不含路径、文件大小、和MD5值完全一致时认为是相同的文件跳过备份。服务器和客户端两端运行完之后总结统计数据。importosimportsocketimportstructimporthashlib IMAGE_EXTS[jpg,jpeg,png,gif,bmp,webp,heic,heif,tiff,ico,avif]VIDEO_EXTS[mp4,mkv,mov,avi,3gp,webm,flv,m4v,mpg,mpeg]MEDIA_EXTSIMAGE_EXTSVIDEO_EXTS# 图片 视频供客户端遍历使用classTcp:def__init__(self,addr,port):self.hostnotaddr self.addraddr self.portport self.connect()defconnect(self):ifself.host:self.serversocket.socket()self.server.bind((,self.port))self.server.listen(5)self.client,(addr,port)self.server.accept()else:self.clientsocket.socket()self.client.connect((self.addr,self.port))defclose(self):self.client.close()ifself.host:self.server.close()defsend(self,data):datadata.encode()ifisinstance(data,str)elsedata self.client.sendall(data)defrecv(self,length):returnself.client.recv(length)defsendlong(self,data):datadata.encode()ifisinstance(data,str)elsedataassertlen(data)132# max 4GBself.send(struct.pack(I,len(data))data)defrecvlong(self):lengthstruct.unpack(I,self.recv(4))[0]# max 4GBdatabytearray()whilelen(data)length:chunkself.client.recv(length-len(data))ifnotchunk:raiseConnectionError data.extend(chunk)returnbytes(data)classFile:def__init__(self,path:str):self.pathos.path.normpath(path).replace(os.sep,/)self.dir,self.basenameos.path.split(self.path)self.stem,self.extos.path.splitext(self.basename)self.info{}propertydefsize(self)-int:ifsizenotinself.info:self.info[size]os.path.getsize(self.path)returnself.info[size]propertydefmd5(self)-str:ifmd5notinself.info:hhashlib.md5()withopen(self.path,rb)asf:forchunkiniter(lambda:f.read(8192),b):h.update(chunk)self.info[md5]h.hexdigest()returnself.info[md5]propertydefmtime(self)-float:ifmtimenotinself.info:self.info[mtime]os.path.getmtime(self.path)returnself.info[mtime]mtime.setterdefmtime(self,value:float):os.utime(self.path,(os.path.getatime(self.path),value))self.info[mtime]valuedef__repr__(self)-str:returnfFile({self.path})def__str__(self)-str:returnself.pathdefLocalIps():返回本机所有可用 IPv4 地址列表ips[]try:ssocket.socket(socket.AF_INET,socket.SOCK_DGRAM)s.connect((8.8.8.8,80))ips.append(s.getsockname()[0])s.close()exceptOSError:passforinfoinsocket.getaddrinfo(socket.gethostname(),None):ipinfo[4][0]if:notinipandip!127.0.0.1andipnotinips:ips.append(ip)returnipsdefPrintLocalIps():打印本机所有可用 IPv4便于手机端填服务器地址print(本机 IP:)foripinLocalIps():print(f{ip})defWalk(paths,exts(,),hiddenTrue):extstuple(ext.lower()forextinexts)forpathinpaths:forroot,folders,filesinos.walk(path):ifnothidden:folders[:][folderforfolderinfoldersifnotfolder.startswith(.)]files[:][fileforfileinfilesifnotfile.startswith(.)]folders.sort()files.sort()forfileinfiles:iffile.lower().endswith(exts):yieldFile(os.path.join(root,file))defHumanSize(n:int)-str:字节数可读化B-PBforunitin(B,KB,MB,GB,TB):ifn1024:returnf{n:.1f}{unit}n/1024returnf{n:.1f}PBdefPrintSummary(st):两端统一的收尾统计发送/跳过的文件个数与总大小print(-*40)print(完成传输:)print(f 发送{st[sent]}个文件总共{HumanSize(st[sent_size])})print(f 跳过{st[skip]}个文件总共{HumanSize(st[skip_size])})defRelpathOf(path:str,roots)-str:算出 path 相对其所属 root 的相对路径便于对端还原目录结构ppath.replace(\\,/)forrinroots:rrr.replace(\\,/).rstrip(/)ifprrorp.startswith(rr/):relp[len(rr)1:]oros.path.basename(p)return(os.path.basename(rr)/rel).replace(\\,/)returnos.path.basename(path)2.2 然后先在电脑上运行 server.py 服务器程序运行后会自动显示本机可用IP地址importosimporttimeimportutil# ----- 配置区 -----SERVER_PORT9000# 预扫描的根目录索引即在这些目录里查重SERVER_SCAN_ROOTS[r.,rpc,# rD:\Pictures,# rD:\Videos,# rE:\Photos,]# 接收文件落盘目录: 日期_时间 文件夹 (如 20260930_123000)NEW_DIRtime.strftime(%Y%m%d_%H%M%S)# ----- 配置区 -----defBuildDatabase(roots):databaselist(util.Walk(roots))print(f已扫描本机文件{len(database)}个建立索引完成。)returndatabasedefUniquePath(path):root,extos.path.splitext(path)i2whileos.path.exists(path):pathf{root}_{i}{ext}i1returnpathdefRecvFile(tcp,relpath:str,size:int):把客户端发来的内容落盘到 落盘目录/相对路径还原文件最后修改时间fileutil.File(UniquePath(os.path.join(NEW_DIR,relpath)))os.makedirs(file.dir,exist_okTrue)withopen(file.path,wb)asf:received0whilereceivedsize:chunktcp.recv(size-received)f.write(chunk)receivedlen(chunk)file.mtimefloat(tcp.recvlong())defRecvFiles(tcp,database):st{sent:0,sent_size:0,skip:0,skip_size:0}whileTrue:cmdtcp.recvlong().decode()ifcmdEND:breakrelpathtcp.recvlong().decode()basenameos.path.basename(relpath)sizeint(tcp.recvlong())md5tcp.recvlong().decode()forfileindatabase:iffile.basenamebasenameandfile.sizesizeandfile.md5md5:tcp.sendlong(SKIP)st[skip]1st[skip_size]sizeprint(f跳过:{relpath}({util.HumanSize(size)}))breakelse:tcp.sendlong(DATA)RecvFile(tcp,relpath,size)st[sent]1st[sent_size]sizeprint(f接收:{relpath}({util.HumanSize(size)}))util.PrintSummary(st)defmain():util.PrintLocalIps()databaseBuildDatabase(SERVER_SCAN_ROOTS)print(f等待手机连接...)tcputil.Tcp(None,SERVER_PORT)RecvFiles(tcp,database)if__name____main__:main()2.3 再然后在手机上运行 client.py 客户端程序输入PC的IP地址后开始备份importutil# ----- 配置区 -----SERVER_PORT9000WALK_ROOTS[phone,/storage/emulated/0/DCIM,/storage/emulated/0/Pictures,# /storage/emulated/0/Movies,# /storage/emulated/0/Download,]CHUNK120# 分块 1MB# ----- 配置区 -----defSendFile(tcp,path:str,size:int,chunk:intCHUNK):按 size 字节流式发送内容1MB/次sent0withopen(path,rb)asf:whilesentsize:dataf.read(chunk)ifnotdata:breaktcp.send(data)sentlen(data)defmain():port,rootsSERVER_PORT,WALK_ROOTS util.PrintLocalIps()hostinput(请输入PC端IP地址: ).strip()print(f连接{host}:{port}...)tcputil.Tcp(host,port)st{sent_size:0,sent:0,skip:0,skip_size:0}forfileinutil.Walk(roots,extsutil.MEDIA_EXTS,hiddenFalse):iffile.size0:continuetcp.sendlong(FILE)relpathutil.RelpathOf(file.path,roots)tcp.sendlong(relpath)tcp.sendlong(str(file.size))tcp.sendlong(file.md5)cmdtcp.recvlong().decode()ifcmdSKIP:st[skip]1st[skip_size]file.sizeprint(f跳过:{relpath}({util.HumanSize(file.size)}))elifcmdDATA:SendFile(tcp,file.path,file.size)tcp.sendlong(str(file.mtime))st[sent]1st[sent_size]file.sizeprint(f发送:{relpath}({util.HumanSize(file.size)}))else:raiseValueError(cmd)tcp.sendlong(END)util.PrintSummary(st)if__name____main__:main()三、其他提醒因为走的是WiFi所以拷贝速度比直连数据线的USB2.0传输速度更快了。如果有需要还可以指定备份例如最近30天新增的文件进一步加快速度请自行修改代码。如果需要将「跳过」的文件改为从硬盘「移动」过来例如你可能在手机上整理了文件夹分类你可能希望同步此变化请自行设计代码。Live Photo的实现原理是一个同名的图片和视频文件存放在了一个文件夹内所以实际拷贝的文件数目可能多于手机上显示的本机照片数量。本版本未实现去除这部分计数统计的方法请自行设计或者以后我有空了可能考虑加进去。本软件不限于在Android手机和PC之间备份在手机↔手机、PC↔PC之间也可以传送备份但是在它们之间使用的意义可能不是很大。本软件具备简单调试功能所以未增加异常处理和断点续传功能备份时请保持网络通畅。如果发生异常报错为保证文件完整建议从新开始备份。这个脚本将来可能会更新如果发生更新将会同步在以下地址本文不再更新znsoooo/tolkits/数据传输/手机同步​
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

成都建设网站制作避坑指南:搞懂备案与代码不踩雷 2026/9/28 9:37:47

成都建设网站制作避坑指南:搞懂备案与代码不踩雷

成都建设网站制作避坑指南:搞懂备案与代码不踩雷 手里拿着域名,看着服务器面板,脑子却像一团浆糊,尤其是到了备案环节,那些“主办单位负责人”、“网站负责人”、“接入商”的名词绕得你头晕。别慌,在成都做网站这几年,我见过太多创业者因为不懂流程,…

阅读更多 →
STC51串口多字节接收实战:状态机、环形缓冲区与中断优化 2026/9/28 9:37:47

STC51串口多字节接收实战:状态机、环形缓冲区与中断优化

1. 项目概述与整体设计思路1.1 STC51串口接收的本质:一次只来一个字节先明确一个基础认知:STC51系列单片机的UART串口,硬件上接收数据时,一次只会往SBUF寄存器里塞一个字节。你不可能指望硬件帮你把一帧多字节数据完整收进来&…

阅读更多 →
WorkBuddy智能体实战:插件、技能与连接器搭建制度学习助手 2026/9/28 9:37:47

WorkBuddy智能体实战:插件、技能与连接器搭建制度学习助手

1. 从一场线下公开课说起:为什么WorkBuddy值得单独拿出来讲上个月我在一场线下公开课上第一次完整接触了WorkBuddy这套AI智能体自动化办公方案。说实话,在此之前我对市面上各种"AI办公助手"已经有点审美疲劳了——大部分产品本质上就是一个套了…

阅读更多 →
基于Python的在线电影推荐系统实战:协同过滤、Flask接口与避坑指南 2026/9/28 9:37:47

基于Python的在线电影推荐系统实战:协同过滤、Flask接口与避坑指南

简介:这是一套面向高校计算机相关专业学生与Python开发初学者的在线电影推荐系统完整项目源码,可作为毕业设计、课程设计或论文配套实践案例,帮助解决个性化推荐算法从理论到落地的问题。压缩包共392个文件,约9.76MB,以…

阅读更多 →
STM32+DMA实现Dshot600协议波形生成与逆向解析 2026/9/28 9:37:47

STM32+DMA实现Dshot600协议波形生成与逆向解析

一直玩惯了飞控直接接电调,很少有人会认真想一下:Dshot 的波形到底是什么样?里面那 16 位数据是怎么编码的?CRC 又是怎么算出来的?我这次借着一块 STM32F103、一个 24MHz 的逻辑分析仪,把 Dshot 协议从底层…

阅读更多 →
WorkBuddy AI智能体自动化办公:从零搭建工作流到Skill封装实战指南 2026/9/28 9:37:41

WorkBuddy AI智能体自动化办公:从零搭建工作流到Skill封装实战指南

1. 从一场线下公开课说起:为什么我要把WorkBuddy AI智能体自动化办公讲透上个月我在本地组织了一场线下公开课,主题就是WorkBuddy AI智能体自动化办公。来的人比预想的多了一倍,有做行政的、做财务的、做运营的,还有几个是自己开公…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉