将内嵌资源经过HASH校验后释放或覆盖外部文件

By admin at 2022-10-26 • 0人收藏 • 416人看过

有这么一个场景: 

软件中把dll和ini文件都内嵌进去了, 这样当客户运行exe的时候自动释放dll和ini到appdata目录中 , 客户用了几天之后.

我们发现之前写的dll里面有bug , 那么需要把新的dll重新打包进exe , 因为appdata目录是隐藏的, 不可能让客户自己去删除原来的dll , 这样就需要运行exe的时候自动释放更新这个dll , 但是不能每次打开exe都去删除之前的释放新的, 这样不合理 , 那么就需要自动判断是否需要更新那个dll 了,

流程方法如下:

  1. 判断目录里有没有那个dll , 没有说明第一次运行exe , 立马释放dll过去

  2. 如果目录里已经存在那个dll , 获取原来dll的哈希值, 和我们exe里面的dll的哈希值比较, 如果相同则说明是最新的,不用更新. 如果不同 , 那么说明原来目录里是旧的需要更新



更新:

经过老大指点 , 如果是释放到appdata目录, 那么可以直接使用io.appData即可

io.appData("\popdes\配置\sys.ini",string.load("\配置\sys.ini"));

image.png

该函数可以比较文件大小和时间戳, 如果不同则自动保存覆盖文件.

这种方式比下面使用HASH值校验速度快的多.

注意:

如果需要把文件释放到其他目录, 或者有不需要每次强制校验更新的文件

那么可以参考io.appData的实现代码自己封装个函数.

我简单封装了个函数, 有需要的看2楼






以下是我之前编写的旧HASH校验代码, 仅用来记录

import fsys;
import crypt;

var fileRelease = function(releasePath,resPath){
	if(!io.exist(releasePath)){
		//不存在,释放
		var str = string.load(resPath);
		string.save(releasePath, str);
	}else {
		//计算旧文件的哈希值
		var oldstr = string.load(releasePath);
		var oldHASH = crypt().hash(oldstr);
		//计算内嵌文件的哈希值
		var newstr = string.load(resPath);
		var newHASH = crypt().hash(newstr);
		//比较两个文件哈希值
		if(oldHASH !== newHASH){
			//文件需更新,则释放
			string.save(releasePath, newstr);
		}
	}	
}

fileRelease(io.appData("\popdes\demo.dll"),"\res\demo.dll");
fileRelease(io.appData("\popdes\配置\sys.ini"),"\配置\sys.ini");


4 个回复 | 最后更新于 2022-11-21
2022-10-26   #1

有时候可能需要释放到其他目录, 而不是appData 那么就将代码

简单封装成了一个通用库 , 增加了是否需要强制校验 , 可以释放到任意目录.

默认:true=每次运行都强制校验, 不相同就删掉并更新

false=只要文件存在即可, 不强制和内嵌文件完全相同


更新:

如楼上所述可以使用io.appData(p,d)可直接释放并校验到appData里, 原理是获取文件的大小和时间戳进行对比校验, 那么我们查看io.appData的实现代码, 然后把我之前写的库给修改下, 提高执行速度. , 库可以改为以下代码:

//释放内嵌文件
namespace releaseFile{
    run = function(releasePath,resPath,update=true){
    	if(!..io.exist(releasePath)){
			//不存在,释放
			..string.save(releasePath,..string.load(resPath));
		}else {
			if(!update){
				//不需要校验, 只要有文件存在就放行
				return;
			}
			//比较长度和时间戳
			var d = ..string.load(resPath);
			var e;
			var f = ..io.open(releasePath,"rb");
			if(f){
				e = f.size()==#d;
				if(e && (d[1]+d[2]==0xA7) ){ 
					var a = ..raw.convert(d,{INT v},60).v + 8;
					f.seek("set",a);
					e = f.read({INT v})[["v"]]===..raw.convert(d,{INT v},a).v; 
				}
				f.close();
			}
			if(!e){
				..string.save(releasePath,d);
			}
		}
	}	
}


/**intellisense()
releaseFile = 内嵌文件释放
releaseFile.run(.(外部文件路径,内嵌资源路径,强制校验) = 执行内嵌文件释放 
end intellisense**/


使用方法是一样的

import releaseFile;

releaseFile.run(io.appData("\popdes\demo.dll"),"\res\demo.dll");
releaseFile.run(io.appData("\popdes\配置\sys.ini"),"\配置\sys.ini",false);






以下是我之前编写的旧HASH校验代码, 仅用来记录

//释放内嵌文件
import crypt;
namespace releaseFile{
    run = function(releasePath,resPath,update=true){
    	if(!..io.exist(releasePath)){
			//不存在,释放
			var str = ..string.load(resPath);
			..string.save(releasePath, str);
		}else {
			if(!update){
				//不需要校验, 只要有文件存在就放行
				return;
			}
			//计算旧文件的哈希值
			var oldstr = ..string.load(releasePath);
			var oldHASH = ..crypt().hash(oldstr);
			//计算内嵌文件的哈希值
			var newstr = ..string.load(resPath);
			var newHASH = ..crypt().hash(newstr);
			//比较两个文件哈希值
			if(oldHASH !== newHASH){
				//文件需更新,则释放
				..string.save(releasePath, newstr);
			}
		}
	}	
}


/**intellisense()
releaseFile = 内嵌文件释放
releaseFile.run(.(外部文件路径,内嵌资源路径,强制校验) = 执行内嵌文件释放 
end intellisense**/

使用方法:

import releaseFile;

releaseFile.run(io.appData("\popdes\demo.dll"),"\res\demo.dll");
releaseFile.run(io.appData("\popdes\配置\sys.ini"),"\配置\sys.ini",false);


2022-10-28   #2

跟着版主新学了一招文件处理的方式

2022-11-17   #3

请问一下,库里面第18行d[1]+d[2]==0xA7代表什么意思?不是很理解。第19行raw.convert(d,{INT v},60).v + 8也有一些蒙,这样就能定位到时间戳的指针吗?


2022-11-21   #4

回复#3 @sunjc :

依葫芦画瓢抄的老大的代码,应该是你理解的意思,只不过相关文章没找到

登录后方可回帖

登 录
信息栏
公 告:

专注分享

谢绝纯提问

谢谢合作!
本站域名:HtmLayout.Cn
aardio可以快速开发上位机,本站主要记录了学习过程中遇到的问题和解决办法及aardio代码分享

这里主要专注于aardio学习交流和经验分享.
纯私人站,当笔记本用的,学到哪写到哪.

Aardio 官方站:Aardio官方
Aardio最新功能:Aardio官方更新日志
本 站 主 站:Stm32cube中文网
Sciter中文在线文档Sciter在线学习文档
空间赞助:才仁机械
打赏本站
Loading...