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

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

有这么一个场景: 

软件中把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 :

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

登录后方可回帖

登 录
信息栏
 私人小站

本站域名

ChengXu.XYZ

投诉联系:  popdes@126.com



快速上位机开发学习,本站主要记录了学习过程中遇到的问题和解决办法及上位机代码分享

这里主要专注于学习交流和经验分享.
纯私人站,当笔记本用的,学到哪写到哪.
如果侵权,联系 Popdes@126.com

友情链接
Aardio官方
Aardio资源网


才仁机械


网站地图SiteMap

Loading...