图书馆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应用与内核编程》 作者:房胜、李旭健、黄…...
保姆级教程:用Python和FFmpeg实战VMAF视频质量评估(附避坑指南)
用PythonFFmpeg实现VMAF视频质量评估的工程实践 视频质量评估一直是多媒体处理领域的关键挑战。当我们需要比较不同编码参数、算法或设备输出的视频质量时,主观的人眼观察不仅效率低下,而且难以标准化。Netflix开源的VMAF(Video Multi-method Assessment…...
extract-video-ppt:基于图像相似度分析的视频幻灯片自动提取解决方案
extract-video-ppt:基于图像相似度分析的视频幻灯片自动提取解决方案 【免费下载链接】extract-video-ppt extract the ppt in the video 项目地址: https://gitcode.com/gh_mirrors/ex/extract-video-ppt 在学术研究、企业培训和在线教育领域,从…...
YOLOv5标注数据可视化检查:用Python脚本批量验证你的bounding box坐标转换是否正确
YOLOv5标注数据可视化检查:用Python脚本批量验证你的bounding box坐标转换是否正确 在目标检测项目中,数据标注的质量直接决定了模型的性能上限。许多工程师花费大量时间调整模型结构和超参数,却忽略了最基础的标注数据验证环节。特别是在使…...
AI核心知识130—大语言模型之 多模态大模型(简洁且通俗易懂版)
如果说我们之前聊的纯文本大模型(如早期的 ChatGPT 或 LLaMA)是极其聪明但被关在小黑屋里的“缸中之脑” (只能靠别人从门缝里递纸条来交流);那么多模态大模型 (Multimodal AI) 就是给这个超级大脑装上了眼睛、耳朵和嘴…...
别再写重复的登录页了!用Vue2.0 + ElementUI封装一个可复用的登录组件(附完整代码)
Vue2.0登录组件封装实战:从重复劳动到高效复用 每次新项目都要重写登录页?是时候告别这种低效开发模式了。在多个后台管理系统并行开发时,登录功能的重复实现不仅浪费时间,更会导致维护成本指数级上升。本文将带你用Vue2.0Elemen…...
51单片机新手必看:用Proteus仿真LM016L液晶屏,从接线到显示完整流程
51单片机与Proteus仿真:LM016L液晶屏从零到显示的实战指南 第一次接触51单片机和Proteus仿真时,面对LM016L液晶屏的接线与显示控制,很多新手都会感到无从下手。屏幕不亮、显示乱码、无法初始化——这些问题看似简单,却往往让初学者…...
激活函数选型指南:从ReLU到RReLU,如何根据你的数据集大小和任务特性做选择?
激活函数实战选型手册:从ReLU到RReLU的深度决策框架 在深度学习模型构建过程中,激活函数的选择往往被当作一个默认参数处理——大多数人会不假思索地选择ReLU。但当我们面对特定任务时,这种"一刀切"的做法可能让模型性能大打折扣。…...
YOLO模型微调实战:从‘炼丹’到‘调参’,手把手教你用WandB可视化找到最佳lr0
YOLO模型微调实战:用WandB可视化找到最佳初始学习率 当你在深夜盯着屏幕上跳动的损失曲线时,是否也曾怀疑过那些"经验值"学习率的可靠性?我清楚地记得第一次微调YOLOv5时的场景——按照教程设置了0.01的学习率,结果模型…...
EagleEye在智慧园区中的创新应用:多目标实时追踪与隐私优先架构设计
EagleEye在智慧园区中的创新应用:多目标实时追踪与隐私优先架构设计 基于 DAMO-YOLO TinyNAS 架构的毫秒级目标检测引擎 1. 项目背景与核心价值 智慧园区作为现代城市发展的重要组成部分,面临着人员流动管理、车辆调度优化、安全监控保障等多重挑战。传…...
【SITS2026权威前瞻】:全球TOP12AI代码引擎实测对比,3大生产级陷阱你避开了吗?
第一章:SITS2026圆桌:智能代码生成未来 2026奇点智能技术大会(https://ml-summit.org) 在SITS2026圆桌论坛上,来自GitHub、Tabnine、DeepMind与国内大模型实验室的七位核心研发者共同探讨了智能代码生成从“补全助手”迈向“协同编程伙伴”…...
