图书馆RFID(射频识别)数据模型压缩/解压缩算法实现小工具
1. 前言
最近闲来无聊,看了一下《图书馆射频识别数据模型第1部分:数据元素的设置及应用规则》以及《图书馆射频识别数据模型第2部分:基于ISO/IEC 15962的数据元素编码方案》,决定根据上面的编码方法实现一下该算法,于是写了一个小工具,本文将围绕这个小工具介绍一下其用法。
2. 详细说明
本程序分别实现了数据的压缩和解压缩两种算法,程序界面如下:

2.1 开发环境
开发工具:Microsoft Visual Studio Community 2022 (64 位) - Current 版本 17.7.6
目标框架:.Net Framework 4.6.2
开发语言:C#
运行环境:Window 10 x86/x64
2.2 数据压缩
馆代码(馆标识):使用馆际互借时用于标识图书馆的唯一编码,格式为:2位国家代码-字母和数字,如:CH-sztsg001。

馆藏地代码:图书馆中用于标识图书所在物理位置的编码,一般由字母和数字组成,如图书馆一楼:tsg001。

应用类别:资料类型以及在图书馆内的用途,参照《图书馆射频识别数据模型第1部分:数据元素的设置及应用规则》中的附录C,这里设置为0x12。

条码号:一般由数字和字母组成,如:TM000000012121。


输入以上信息后,点击压缩,程序会根据条码的数据类型选择相应的压缩算法进行数据压缩,并输出压缩后的结果。压缩算法可参照《图书馆射频识别数据模型第2部分:基于ISO/IEC 15962的数据元素编码方案》中关于数据编码的部分内容。
2.3 数据解压缩
将压缩后的数据输入至文本框中,点击加压缩即可,程序会自动解析数据,并将结果呈现至馆代码、馆藏地点、应用类别、条码号中。

3. 代码
3.1 压缩算法
/// <summary>/// 数据压缩/// </summary>/// <param name="dataType">数据类型(如:条码号 DataTyep.Barcode)</param>/// <param name="data">数据内容</param>/// <param name="userDefineCompressFormat">是否使用自定义压缩模式</param>/// <param name="defaultFormat">自定义压缩模式</param>/// <returns></returns>private static byte[] DataCompress(string data, bool userDefineCompressFormat = false, CompressModel defaultFormat = CompressModel.Number){try{if (data == null || data == ""){return null;}CompressModel format = defaultFormat;if (userDefineCompressFormat){format = defaultFormat;//压缩类型}else{format = GetDataCompressFormat(data);//压缩类型}byte[] btData = null;switch (format){case CompressModel.ISIL:btData = GetConverData0(data);break;case CompressModel.IntNumber:btData = GetConverData1(data);break;case CompressModel.Number:btData = GetConverData2(data);break;case CompressModel.CP_5Bit:btData = GetConverData3(data);break;case CompressModel.CP_6Bit:btData = GetConverData4(data);break;case CompressModel.CP_7Bit:btData = GetConverData5(data);break;case CompressModel.CP_8bit:btData = GetConverData6(data);break;default:btData = Encoding.UTF8.GetBytes(data);break;}if (btData == null){return null;}return btData;}catch (Exception ex){}return null;}/// <summary>/// 获取压缩后的数据/// </summary>/// <param name="orgDataDic"></param>/// <returns></returns>public static byte[] GetCompressData(Dictionary<DataType, string> orgDataDic){try{//每个数据集均由前导字节、编码数据长度、被压缩数据3部分组成Dictionary<DataType, RfidData> cmpDataDic = new Dictionary<DataType, RfidData>();int nDataTotalLen = 0;foreach (var key in orgDataDic.Keys){RfidData data = new RfidData();//馆代码采用固定的ISIL方式编码if (key == DataType.LibraryCode){data.compressFormat = CompressModel.ISIL;}//直接使用8位编码else if (key == DataType.UseType || key == DataType.LocationCode || key == DataType.ONIXMediaFormat){data.compressFormat = CompressModel.CP_8bit;}else{data.compressFormat = GetDataCompressFormat(orgDataDic[key]);}data.strData = orgDataDic[key];if (string.IsNullOrEmpty(data.strData)){continue;}//如果数据大于最大的整数,则采用数字压缩if (data.compressFormat == CompressModel.IntNumber && data.strData.Length >= 18){data.compressFormat = CompressModel.Number;}byte[] btData = DataCompress(orgDataDic[key], true, data.compressFormat);byte nAppLen = 0;byte btFirstByte = 0;bool bFlag = CheckFirstByteData(data.compressFormat, key, btData, out btFirstByte, out nAppLen);//如果为条码号则需要进行填充判断if (key == DataType.BarCode && bFlag){data.byteData = new byte[btData.Length + 3 + nAppLen];//前导符(1byte) + 偏移量(1byte) + 压缩数据长度(1byte) + 填充数据长度(nAppLen)data.byteData[0] = btFirstByte;data.byteData[1] = nAppLen;data.byteData[2] = (byte)btData.Length;Array.Copy(btData, 0, data.byteData, 3, btData.Length);}else{data.byteData = new byte[btData.Length + 2];//前导符(1byte) + 压缩数据长度(1byte)data.byteData[0] = GetFirstByteData(data.compressFormat, key);data.byteData[1] = (byte)btData.Length;Array.Copy(btData, 0, data.byteData, 2, btData.Length);}nDataTotalLen += data.byteData.Length;//数据总长度cmpDataDic.Add(key, data);}return GetFullCompressData(ref cmpDataDic, nDataTotalLen);}catch (Exception ex){ }return null;}
注:以上仅为部分代码。
3.2 解压缩算法
/// <summary>
/// 解压一个数据块
/// </summary>
/// <param name="btDecData">待解压的数据</param>
/// <param name="nDecType">数据压缩方式</param>
/// <param name="nDataType">数据类型</param>
/// <param name="nDataLen">数据长度</param>
/// <returns></returns>
private static RfidData DataDeCompress(byte[] btDecData, int nDecType, int nDataType)
{try{RfidData data = new RfidData();string strDecData = string.Empty;switch (nDecType){case (int)CompressModel.ISIL:if ((DataType)nDataType == DataType.LibraryCode){strDecData = GetExplodeDate0(btDecData);}else{strDecData = GetExplodeDate6(btDecData);}break;case (int)CompressModel.IntNumber:strDecData = GetExplodeDate1(btDecData);break;case (int)CompressModel.Number:strDecData = GetExplodeDate2(btDecData);break;case (int)CompressModel.CP_5Bit://五位码strDecData = GetExplodeDate3(btDecData);break;case (int)CompressModel.CP_6Bit:strDecData = GetExplodeDate4(btDecData);break;case (int)CompressModel.CP_7Bit:strDecData = GetExplodeDate5(btDecData);break;case (int)CompressModel.CP_8bit:strDecData = GetExplodeDate6(btDecData);break;}DataType dataType = (DataType)nDataType;data.byteData = btDecData;data.compressFormat = (CompressModel)nDecType;data.strData = strDecData;return data;}catch (Exception ex){}return null;
}/// <summary>
/// 解压缩
/// </summary>
/// <param name="strData">16进制(大写)被压缩后的数据</param>
/// <returns></returns>
public static Dictionary<DataType, RfidData> DataDeCompress(string strData)
{try{if (string.IsNullOrEmpty(strData)){return null;}Dictionary<DataType, RfidData> dataDic = new Dictionary<DataType, RfidData>();int nIdx = 0;byte[] btData = StringToByte(strData);do{//取第一个字节和第二个字节byte btFirstData = btData[nIdx];byte btDataLen = 0;nIdx += 1;int nAppLen = 0;//填充数据长度int nDecType = 0;//压缩类型int nDataType = 0;//数据类型byte[] btDecData;//压缩后的数据//判断数据是否有填充和偏移bool bAppFlag = CheckDataAppend(btFirstData, out nDecType, out nDataType);if (nDataType == 0)//有问题的数据块直接算是有效数据终止{break;}if (bAppFlag){nAppLen = btData[nIdx];nIdx += 1;//跳过填充字节btDataLen = btData[nIdx];//标示数据长度nIdx += 1;//跳过数据长度字节//压缩后的数据btDecData = new byte[btDataLen];Array.Copy(btData, nIdx, btDecData, 0, btDataLen);nIdx = nIdx + btDataLen + nAppLen;}else{btDataLen = btData[nIdx];//标示数据长度nIdx += 1;//跳过数据长度字节if (nIdx + btDataLen >= btData.Length){break;}//压缩后的数据btDecData = new byte[btDataLen];Array.Copy(btData, nIdx, btDecData, 0, btDataLen);nIdx += btDataLen;}DataType dataType = (DataType)nDataType;RfidData data = DataDeCompress(btDecData, nDecType, nDataType);if (nDataType > 0 && nDataType < (int)DataType.NotUseFlag){if (!dataDic.ContainsKey(dataType)){dataDic.Add(dataType, data);}}}while (nIdx < btData.Length);return dataDic;}catch (Exception ex){}return null;
}
注:以上仅为部分代码。
4. 总结
程序主要包括两部分的功能:压缩与解压缩,将压缩后的数据作为输入数据可执行解压缩操作,也可用于将使用了支持标准的图书馆射频识别数据模型算法加密的数据进行解压缩,文章中提及的算法代码均为压缩或解压缩代码中的一部分。
4.1 参考资料1
《图书馆射频识别数据模型第1部分:数据元素的设置及应用规则》

4.2 参考资料2
《图书馆射频识别数据模型第2部分:基于ISO/IEC 15962的数据元素编码方案》

相关文章:
图书馆RFID(射频识别)数据模型压缩/解压缩算法实现小工具
1. 前言 最近闲来无聊,看了一下《图书馆射频识别数据模型第1部分:数据元素的设置及应用规则》以及《图书馆射频识别数据模型第2部分:基于ISO/IEC 15962的数据元素编码方案》,决定根据上面的编码方法实现一下该算法,于…...
【Java Web基础】一些网页设计基础(三)
文章目录 1. 导航栏样式进一步调整2. 入驻企业信息展示栏2.1 Title设置2.2 具体信息添加 3. 轮播图4. 注册登录按钮及其他信息5. 一些五颜六色的、丰富视觉效果的中间件…… 1. 导航栏样式进一步调整 这种导航栏,选中的时候字体变蓝色,可能还是不够美观&…...
2 使用GPU理解并行计算
2.1 简介 本章旨在对并行程序设计的基本概念及其与GPU技术的联系做一个宽泛的介绍。本章主要面向具有串行程序设计经验,但对并行处理概念缺乏了解的读者。我们将用GPU的基本知识来讲解并行程序设计的基本概念。 2.2 传统的串行代码 绝大多数程序员是在串行程序占据…...
Android什么情况下会出现内存泄漏以及怎么解决?
1.什么情况下会出现内存泄漏? (1)单例模式下为什么会造成内存泄漏? 因为单例的生命周期和应用的生命周期是一致的,如果往单例模式里面传了一个生命周期比较短的对象,比如Activity,就会导致Activity不能释放,导致内存泄漏。我们可以传context.getAppliactionContext,而…...
kafka集群介绍及搭建
介绍 kafka是一个高性能、低延迟、分布式的消息传递系统,特点在于实时处理数据。集群由多个成员节点broker组成,每个节点都可以独立处理消息传递和存储任务。 路由策略 发布消息由key、value组成,真正的消息是value,key是标识路…...
2024/03/19(网络编程·day5)
一、思维导图 二、selec函数实现TCP并发服务器 #include<myhead.h>#define SER_PORT 8888 //服务器端口号 #define SER_IP "192.168.117.116" //服务器IP int main(int argc, const char *argv[]) {//1、创建一个套接字int sfd -1;sfd socket(AF_INET,SOC…...
LeetCode解法汇总1969. 数组元素的最小非零乘积
目录链接: 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目: https://github.com/September26/java-algorithms 原题链接:. - 力扣(LeetCode) 描述: 给你一个正整数 p 。你有一个下标从 1 开…...
学习vue3第九节(新加指令 v-pre/v-once/v-memo/v-cloak )
1、v-pre 作用:防止编译器解析某个特定的元素及其内容,即v-pre 会跳过当前元素以及其子元素的vue语法解析,并将其保持原样输出; 用于:vue 中一些没有指令和插值表达式的节点的元素,使用 v-pre 可以提高 Vu…...
二开飞机机器人群发,实现自动给多个频道发送消息
频道1 频道2 二开代码部分: const CChatIdListprocess.env.CHANNEL_CHAT_ID_LIST; var channelChatIdArray CChatIdList.split(,);channelChatIdArray.forEach(function(item) {console.log(item); // 这里可以替换为您需要对数组中每个值进行的操作bot.sendM…...
AI如何支持慈善组织
为各种有意义的事业提供支持,无论是努力寻找治愈疾病的方法、研发使生活更轻松的技术,还是为有需要的人提供服务,都是无比崇高的使命。提供捐款或是投入时间支持的捐助者和志愿者往往对他们选择支持的事业的目标、服务和资源分配存有诸多疑虑…...
Git如何清除账户凭证
场景:一般发生在Git用户变更的情况 1.git base 操作 Git会使用凭证助手 credential.helper来储存账户凭证,通过以下命令移除: git config --system --unset credential.helper 除了system系统级外,还有 global、local范围。 查…...
【YUNBEE云贝-PostgreSQL】FDW应用
注: 本文为云贝教育 刘峰 原创,请尊重知识产权,转发请注明出处,不接受任何抄袭、演绎和未经注明出处的转载。 前言 Wrapper(FDW)是一项关键特性,它赋予数据库用户直接通过SQL语句访问存储于外部数据源的能…...
Spring MVC文件上传配置
版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl 文件上传 Spring MVC文件上传基于Servlet 3.0实现;示例代码如下: Overrideprotected void customizeRegistration(ServletRegistration.Dynamic reg…...
JavaScript高级(十八)---进程和线程,宏任务和微任务
进程和线程 进程(process):计算机已经运行的程序,是操作系统管理程序的一种方式,我们可以认为,启动一个应用程序,就会默认启动一个进程(也可能是多个进程)。 线程&…...
How to install mongodb on redhat 7.7
下载rpm: mongodb-enterprise-server-6.0.3-1.el7.x86_64.rpmmongodb-org-server-6.0.4-1.el7.x86_64.rpmmongodb-mms-6.0.9.100.20230201T2148Z.x86_64.rpm rpm -ivh mongodb-org-server-6.0.4-1.el7.x86_64.rpm rpm -ivh mongodb-mms-6.0.9.100.20230201T2148Z.x86_64.rpm …...
关于继承是怎么样的?那当然是很好理解之
本文描述了关于继承的大部分知识,但是并不全,每篇博客之间的知识都有互串,所以需要把几篇文章合起来看,学会融会贯通! 温馨提示:使用PC端观看,效果更佳! 目录 1.继承是什么 2.什…...
高可用系统有哪些设计原则
1.降级 主动降级:开关推送 被动降级:超时降级 异常降级 失败率 熔断保护 多级降级2.限流 nginx的limit模块 gateway redisLua 业务层限流 本地限流 gua 分布式限流 sentinel 3.弹性计算 弹性伸缩—K8Sdocker 主链路压力过大的时候可以将非主链路的机器给…...
LeetCode-回文数
LeetCode-回文数 解体思路: ①第一种:转换成字符串,使用字符串的现有api方法进行反转 ②第二种:直接使用循环除余乘10方法,进行反转 涉及知识点: 循环判断,StringBuffer,int类型…...
50. 【Linux教程】源码安装软件
本小节介绍如何使用软件的源码包安装软件,以安装 nginx 源码包为例。 1.下载软件源码包 使用如下命令下载 nginx 源码包: wget http://nginx.org/download/nginx-1.18.0.tar.gz执行结果如下图所示: 2.解压源码包 下载好了压缩包之后&#…...
《操作系统实践-基于Linux应用与内核编程》第10章--实验 Qt聊天程序
前言: 内容参考《操作系统实践-基于Linux应用与内核编程》一书的示例代码和教材内容,所做的读书笔记。本文记录再这里按照书中示例做一遍代码编程实践加深对操作系统的理解。 引用: 《操作系统实践-基于Linux应用与内核编程》 作者:房胜、李旭健、黄…...
Splatoon插件架构革新:FFXIV高难度副本智能导航与机制破解技术实现
Splatoon插件架构革新:FFXIV高难度副本智能导航与机制破解技术实现 【免费下载链接】Splatoon An accessibility tool to assist in gameplay and compensate for human imperfections. 项目地址: https://gitcode.com/gh_mirrors/spl/Splatoon Splatoon作为…...
从老古董NE555到单片机:手把手教你做一个简易数字频率计(STC89C52)
从NE555到STC89C52:打造高性价比数字频率计的完整指南 在电子爱好者的世界里,测量信号频率是一项基础却至关重要的技能。想象一下,当你调试一个振荡电路时,能够实时看到信号频率的变化;或者当你需要验证一个传感器输出…...
Material Icon Library开源贡献指南:如何参与项目开发和维护
Material Icon Library开源贡献指南:如何参与项目开发和维护 【免费下载链接】material-icon-lib Library containing over 2000 material vector icons that can be easily used as Drawable or as a standalone View. 项目地址: https://gitcode.com/gh_mirrors…...
URDF还是SDF?给ROS1/ROS2开发者的Gazebo模型格式选择指南(含避坑建议)
URDF还是SDF?给ROS1/ROS2开发者的Gazebo模型格式选择指南(含避坑建议) 当你在Gazebo中调试机器人模型时,是否遇到过这些情况:精心设计的URDF模型导入后突然沉入地面,关节运动方向完全错乱,或是发…...
从‘线性估计’的工程应用反推:为什么机器学习中的梯度下降要求函数可微?
梯度下降为何要求函数可微?从工程视角看数学约束 在机器学习项目的实际开发中,我们常常不假思索地调用现成的优化器,比如TensorFlow的AdamOptimizer或PyTorch的SGD。这些优化器的核心都是梯度下降算法,而所有梯度下降的实现都隐含…...
php-qrcode实战教程:如何为二维码添加Logo和背景图片
php-qrcode实战教程:如何为二维码添加Logo和背景图片 【免费下载链接】php-qrcode A PHP QR Code generator and reader with a user-friendly API. 项目地址: https://gitcode.com/gh_mirrors/ph/php-qrcode php-qrcode是一个功能强大的PHP二维码生成和读取…...
金融评分卡是一种将用户信用风险量化为分数的模型工具,广泛应用于贷款审批、额度定价和风险预警等环节,分数越高代表风险越低
金融评分卡是一种将用户信用风险量化为分数的模型工具,广泛应用于贷款审批、额度定价和风险预警等环节,分数越高代表风险越低。一、评分卡的核心作用金融机构通过评分卡快速判断:是否授信(如信用卡申请)授信额度与…...
C# 14 AOT 部署 Dify 客户端:为什么92%的.NET团队在GA前就踩坑?3个被官方文档隐藏的关键配置
第一章:C# 14 AOT 部署 Dify 客户端的演进逻辑与生产必要性随着 AI 应用边界持续拓展,轻量、安全、可嵌入的客户端成为关键基础设施。Dify 作为开源 LLM 应用编排平台,其官方 SDK 主要面向 Python 和 JavaScript 生态;而企业级桌面…...
3步实现CATIA几何特征智能识别:工业软件二次开发提升设计效率指南
3步实现CATIA几何特征智能识别:工业软件二次开发提升设计效率指南 【免费下载链接】pycatia python module for CATIA V5 automation 项目地址: https://gitcode.com/gh_mirrors/py/pycatia 在现代CAD设计流程中,工程师经常需要处理大量重复的几何…...
Primo内置代码编辑器深度解析:实时预览与智能开发体验
Primo内置代码编辑器深度解析:实时预览与智能开发体验 【免费下载链接】primo Component-based CMS with a built-in IDE, visual editing, and static site generation. One server, unlimited sites. 项目地址: https://gitcode.com/gh_mirrors/pr/primo P…...
