C# 学习笔记(12)hex文件转bin文件小工具

hex文件格式

hex文件格式网上有很多
我这里参考HEX文件格式详解https://blog.csdn.net/weixin_39752827/article/details/81477686

编写hex2bin类

hex转bin文件的方法很多,但是在做bootLoader工具时,只能接受bin文件就很烦,就有了将hex转bin集成到自己工具里的想法。
首先去github找了一下,避免重复造轮子,发现了两个不错的c#示例
Hex2Bin https://github.com/x893/Hex2Bin
STM32-IAP-HEX-Merge https://github.com/SmartElec/STM32-IAP-HEX-Merge
但是不太满意,刚好又在学习c#,就动手自己造了个轮子

using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace CSharp_Hex2Bin
{/// <summary>/// hex文件转bin文件 /// hex格式解析:<0x3a>[数据长度1Byte][数据地址2Byte][数据类型1Byte][数据nByte][校验1Byte]<0x0d><0x0a>/// </summary>public static class MyHex2Bin{/// <summary>/// hex文件段信息结构体/// </summary>public class Section{public uint startAddr = new uint();public uint endAddr = new uint();public List<byte> data = new List<byte>();public string filePath;}/// <summary>/// hex 数据类型/// </summary>enum INTEL_COMMAND : byte{UNKNOWN = 0xFF,/// <summary>/// Data Record 数据/// </summary>DATA = 0x00,/// <summary>/// End of File Record 文件结束标志/// </summary>EOF = 0x01,/// <summary>/// Extended Segment Address Record 延伸段地址/// </summary>EXT_SEGMENT_ADDR = 0x02,/// <summary>/// Start Segment Address Record   起始延伸地址/// </summary>SEGMENT_ADDR = 0x03,/// <summary>/// Extended Linear Address Record 扩展线性地址 也就是基地址/// </summary>EXTEND_ADDR = 0x04,/// <summary>/// Start Linear Address Record       程序起始地址也就是程序入口地址(main)/// </summary>LINEAR_ADDR = 0x05,DATA_LOOP = 0x10}/// <summary>/// 根据hex文件生成bin文件, 不管hex文件是否有问题 /// </summary>/// <param name="outBinFilePath">bin文件路径</param>/// <param name="encoding">hex文件编码格式</param>/// <param name="ignoreByte">占位符 空白的地址填</param>/// <param name="sections">hex文件信息</param>/// <param name="log">日志信息</param>/// <param name="errSections">有问题的地址块</param>/// <param name="inHexFilePath">hex文件路径</param>public static void Conver(string outBinFilePath, Encoding encoding, byte ignoreByte, ref List<Section> sections, out string log, ref List<Section> errSections, params string[] inHexFilePath){LoadHex(encoding, ref sections, out log, ref errSections, inHexFilePath);WriteBinFile(outBinFilePath, ignoreByte, sections);}/// <summary>/// 根据hex文件生成bin文件, 不管hex文件是否有问题 /// </summary>/// <param name="outBinFilePath">bin文件路径</param>/// <param name="inHexFilePath">hex文件路径</param>public static void Conver(string outBinFilePath, params string[] inHexFilePath){List<Section> sections = new List<Section>();List<Section> errSections = new List<Section>();Conver(outBinFilePath, Encoding.Default, 0, ref sections, out string log, ref errSections, inHexFilePath);}/// <summary>/// 根据hex文件生成bin文件, 不管hex文件是否有问题 /// </summary>/// <param name="inHexFilePath">hex文件路径</param>public static void Conver(params string[] inHexFilePath){Conver(inHexFilePath[0], inHexFilePath);}/// <summary>/// 将hex文件读到内存中/// </summary>/// <param name="encoding">hex文件编码格式</param>/// <param name="sections">hex文件信息</param>/// <param name="log">日志</param>/// <param name="errSections">有问题的地址块</param>/// <param name="inHexFilePath">hex文件路径</param>public static void LoadHex(Encoding encoding, ref List<Section> sections, out string log, ref List<Section> errSections, params string[] inHexFilePath){//加载hex文件LoadHex(encoding, ref sections, out log, inHexFilePath);//检查地址冲突if (!CheckAddr(sections, out string str, ref errSections)){log += str;}}/// <summary>/// 将hex文件读到内存中/// </summary>/// <param name="encoding">hex文件编码格式</param>/// <param name="sections">hex文件信息</param>/// <param name="log">日志</param>/// <param name="inHexFilePath">hex文件路径</param>public static void LoadHex(Encoding encoding, ref List<Section> sections, out string log, params string[] inHexFilePath){log = "";foreach (var item in inHexFilePath){if (!string.IsNullOrWhiteSpace(item)){//文件存在并且以.hex结尾if (File.Exists(item) && Path.GetExtension(item).ToLower().Equals(".hex")){#region 解析一个hex文件//读取hex文件string[] hexFileAllLines = File.ReadAllLines(item, encoding);List<Section> tempSections = new List<Section>();uint extend_address = 0, start_address = 0, segment_address = 0, linear_address = 0;uint count = 0, address = 0;byte dataType = 0;INTEL_COMMAND command = INTEL_COMMAND.UNKNOWN;for (int line = 0; line < hexFileAllLines.Length; line++){bool fail = false;string hexFileLine = hexFileAllLines[line];//hex文件每行最少11个字符并且以":"起始if (hexFileLine.Length >= 11 && hexFileLine.StartsWith(":") && CheckSum(hexFileLine)){#region 解析一行hex文件 获取其长度、地址、数据类型、校验和信息fail |= !uint.TryParse(hexFileLine.Substring(1, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out count);fail |= !uint.TryParse(hexFileLine.Substring(3, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out address);fail |= !byte.TryParse(hexFileLine.Substring(7, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out dataType);command = (INTEL_COMMAND)dataType;if (fail){log += "文件: " + item + " 第" + line + "行\r\n" + hexFileLine + "\r\n不符合hex文件格式!解析失败\r\n";break;}#endregion}else{log += "文件: " + item + " 第" + line + "行\r\n" + hexFileLine + "\r\n不符合hex文件格式!\r\n";continue;}switch (command){case INTEL_COMMAND.EOF:sections.AddRange(tempSections);log += "文件: " + item + " 解析完成 共解析:" + line + "行\r\n";line = hexFileAllLines.Length;break;case INTEL_COMMAND.DATA:#region 正常数据接收case INTEL_COMMAND.DATA_LOOP:int idx = 9; //hex文件 第九个字符开始才是数据if (tempSections.Count > 0){if (string.IsNullOrEmpty(tempSections[tempSections.Count - 1].filePath)){tempSections[tempSections.Count - 1].startAddr = segment_address + extend_address + address;tempSections[tempSections.Count - 1].endAddr = tempSections[tempSections.Count - 1].startAddr;tempSections[tempSections.Count - 1].filePath = item;}else if ((tempSections[tempSections.Count - 1].endAddr - (segment_address + extend_address) + 1) != address){tempSections.Add(new Section());tempSections[tempSections.Count - 1].startAddr = segment_address + extend_address + address;tempSections[tempSections.Count - 1].endAddr = tempSections[tempSections.Count - 1].startAddr;tempSections[tempSections.Count - 1].filePath = item;}}for (; !fail && count > 0; --count){fail = !byte.TryParse(hexFileLine.Substring(idx, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out byte data);if (!fail){tempSections[tempSections.Count - 1].data.Add(data);tempSections[tempSections.Count - 1].endAddr = segment_address + extend_address + address;}else{fail = true;}idx += 2;address++;}break;#endregioncase INTEL_COMMAND.EXT_SEGMENT_ADDR:#region 延伸段地址解析if (count != 2 || hexFileLine.Length != 15){fail = true;log += string.Format("文件: {0} 第 {1} 行: {2}  延伸段地址解析错误\r\n", item, line.ToString(), hexFileLine);}else{fail |= !uint.TryParse(hexFileLine.Substring(9, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out segment_address);if (fail)log += string.Format("文件: {0} 第 {1} 行:{2}  延伸段地址解析错误\r\n", item, line.ToString(), hexFileLine);else{segment_address <<= 4;tempSections.Add(new Section());}}break;#endregioncase INTEL_COMMAND.SEGMENT_ADDR:#region 起始段地址解析if (count != 4){log += string.Format("文件: {0} 第 {1} 行: {2}  起始段地址解析错误\r\n", item, line.ToString(), hexFileLine);}else{fail |= !uint.TryParse(hexFileLine.Substring(9, 8), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out start_address);if (fail)log += string.Format("文件: {0} 第 {1} 行: {2}  起始段地址解析错误\r\n", item, line.ToString(), hexFileLine);elselog += string.Format("文件: {0} 第 {1} 行: 起始段地址解析成功: 0x{2:X}\r\n", item, line.ToString(), start_address);}break;#endregioncase INTEL_COMMAND.EXTEND_ADDR:#region 扩展段地址解析if (hexFileLine.Length != 15){log += string.Format("文件: {0} 第 {1} 行: {2}  扩展段地址解析错误\r\n", item, line.ToString(), hexFileLine);fail = true;}else{fail |= !uint.TryParse(hexFileLine.Substring(9, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out extend_address);if (fail){log += string.Format("文件: {0} 第 {1} 行: {2}  扩展段地址解析错误\r\n", item, line.ToString(), hexFileLine);}else{extend_address = extend_address << 16;tempSections.Add(new Section());}}break;#endregioncase INTEL_COMMAND.LINEAR_ADDR:#region 程序起始地址也就是程序入口地址(main)解析if (count != 4){log += string.Format("文件: {0} 第 {1} 行: {2}  程序起始地址解析错误\r\n", item, line.ToString(), hexFileLine);}else{fail |= !uint.TryParse(hexFileLine.Substring(9, 8), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out linear_address);if (fail)log += string.Format("文件: {0} 第 {1} 行: {2}  程序起始地址解析错误\r\n", item, line.ToString(), hexFileLine);elselog += string.Format("文件: {0} 第 {1} 行: 程序起始地址解析成功: 0x{2:X}\r\n", item, line.ToString(), linear_address);}break;#endregiondefault:log += "文件: " + item + " 第" + line + "行\r\n" + hexFileLine + "\r\n不符合hex文件格式!\r\n";fail = true;break;}if (fail){log += "文件: " + item + " 第" + line + "行\r\n" + hexFileLine + "\r\n不符合hex文件格式!\r\n";break;}}#endregion}else{log += "文件: " + item + "不存在或不是.hex文件!\r\n";}}}}/// <summary>/// 校验hex文件一行数据 /// </summary>/// <param name="hexLine">hex一行数据</param>/// <returns>true 校验成功</returns>public static bool CheckSum(string hexLine){bool fail = false;byte sum = 0;byte data = 0;for (int i = 1; i < hexLine.Length - 2; i += 2){fail |= !byte.TryParse(hexLine.Substring(i, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out data);sum += data;}fail |= !byte.TryParse(hexLine.Substring(hexLine.Length - 2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out data);if ((byte)(0x100 - sum) == data && !fail){return true;}return false;}/// <summary>/// 检查地址是否有OK/// </summary>/// <param name="sections"></param>/// <param name="log">日志信息</param>/// <param name="errSections">有问题的地址块</param>/// <returns>true 地址信息没问题</returns>public static bool CheckAddr(List<Section> sections, out string log, ref List<Section> errSections){log = "";bool err = true;//排序sections.Sort((x, y) => x.startAddr.CompareTo(y.startAddr));//每个存储块 数据个数和地址信息是否一致for (int i = 0; i < sections.Count; i++){if (sections[i].startAddr + sections[i].data.Count -1 != sections[i].endAddr){errSections.Add(sections[i]);log += string.Format("文件: {2}  地址块:0x{0:x8}--0x{1:x8} 数据出错\r\n", sections[i].startAddr, sections[i].endAddr, sections[i].filePath);err = false;}}//存储块之间是否有重叠for (int i = 1; i< sections.Count; i++){if(sections[i].startAddr < sections[i-1].endAddr){errSections.Add(sections[i-1]);errSections.Add(sections[i]);log += string.Format("文件: {4} 和 文件: {5} 地址冲突:0x{0:x8}--0x{1:x8} 和 0x{2:x8}--0x{3:x8}\r\n", sections[i - 1].startAddr, sections[i - 1].endAddr, sections[i].startAddr, sections[i].endAddr, sections[i - 1].filePath, sections[i].filePath);err = false;}}return err;}/// <summary>/// 将地址块数据写入到文件中/// </summary>/// <param name="outBinFilePath">输出文件路径</param>/// <param name="ignoreByte">占位符 空白的地址填</param>/// <param name="sections">hex文件块信息</param>public static void WriteBinFile(string outBinFilePath, byte ignoreByte, List<Section> sections){uint startAddr = sections[0].startAddr;int size = (int)(sections[sections.Count - 1].endAddr - startAddr) + 1;if(size > 1024*1024*20){return;}byte[] binFile = new byte[size];ArrayList.Repeat(ignoreByte, size).CopyTo(binFile);//将地址块信息写入到内存数组中foreach (var item in sections){item.data.ToArray().CopyTo(binFile, item.startAddr - startAddr);}if (Path.GetExtension(outBinFilePath).ToLower() != ".bin"){outBinFilePath = Path.ChangeExtension(outBinFilePath, ".bin");}File.WriteAllBytes(outBinFilePath, binFile);}/// <summary>/// 将地址块数据写入到文件中/// </summary>/// <param name="sections">hex文件块信息</param>public static void WriteBinFile(List<Section> sections){WriteBinFile(sections[0].filePath, 0xff, sections);}}
}

软件使用

根据上面的hex2bin类,编写了一个简单的示例,hex2bin小工具

  1. 可以将hex文件拖拽到软件打开
  2. 可以将未指定的flash地址填充未0
  3. 可以分析hex文件地址信息


源码地址 https://github.com/mian2018/CSharp_Hex2Bin

C# 学习笔记(12)hex文件转bin文件小工具相关推荐

  1. 点云学习笔记19——使用pcl将bin文件转化为pcd文件

    从KITTI下载的数据是二进制bin格式,但是pcl似乎只能读取pcd文件,为了可视化,先将bin文件转换为pcd文件. 在home下,新建文件夹PointCloud(我建在这里,大家随意),在Poi ...

  2. Linux学习笔记12——配置ftp、squid、Tomcat、Samba、MySQL主从

    Linux学习笔记12 Linux学习笔记12 配置FTP服务 配置pure-ftpd 开机启动 上传下载文件 配置vsftpd CentOS 70安装配置Vsftp服务器 搭好vsftp之后出现55 ...

  3. ros学习笔记12——python实现发布和接收ros topic

    ros学习笔记12--python实现发布和接收ros topic 一.简单demo 1.工作空间是存放工程开发的相关文件的文件夹 2.创作工作空间指令 3 .创建功能包 4. 创建Topic的订阅发 ...

  4. hex文件和bin文件区别

    HEX文件和BIN文件是我们经常碰到的2种文件格式.因为自己也是新手,所以一直对这两个文件懵懵懂懂,不甚了解,最近在做STM32单片机的IAP更新,其中要考虑HEX文件和BIN文件,所以需要学习下这两 ...

  5. Python 学习笔记(3)对txt文件的读与写操作(下)

    上一章节我们讨论了如何对txt文本文件进行读写操作,这一张将讨论如何进行二进制文件的写与读.<Python 学习笔记(3)对txt文件的读与写操作(上)>的链接如下https://blog ...

  6. FPGA学习笔记之Altera FPGA使用JIC文件配置固化教程

    FPGA学习笔记之Altera FPGA使用JIC文件配置固化教程 很多做过单片机的朋友都知 道,我们在对MCU烧写完程序固件后,那么该程序固件就存储在了该MCU内部.即使MCU断电了再重新上电,程序 ...

  7. golang学习笔记12 beego table name `xxx` repeat register, must be unique 错误问题

    golang学习笔记12 beego table name `xxx` repeat register, must be unique 错误问题 今天测试了重新建一个项目生成新的表,然后复制到旧的项目 ...

  8. oracle 怎么看监听文件,【学习笔记】Oracle11G关于监听文件位置与监听文件大小限制...

    [学习笔记]Oracle11G关于监听文件位置与监听文件大小限制 时间:2016-11-07 21:21   来源:Oracle研究中心   作者:HTZ   点击: 次 天萃荷净 Oracle研究中 ...

  9. axf文件、hex文件、bin文件区别

    axf文件.hex文件与bin文件都可以运行在stm32,都存储了源代码通过编译器生成的机器码. axf文件:编译默认生成的文件,包含代码数据和调试信息,在MDK里进行debug调试用的文件. hex ...

最新文章

  1. Linux之SSH性能调优,防止连接等待时间过长,连接速度飞起
  2. 如何在全局程序集缓存 (GAC) 中安装 DLL 文件
  3. 苹果隐藏应用_使用iMazing导出苹果设备中的录音文件
  4. [Python图像处理] 十九.图像分割之基于K-Means聚类的区域分割
  5. MongoDB的查询操作
  6. iBatis 到 MyBatis区别
  7. 阿里云对数据可靠性保障的一些思考
  8. ubuntu grub 操作
  9. 001_关于选中的磁盘具有MBR分区表。在 EFI 系统上,Windows 只能安装到 GPT 磁盘。问题解决
  10. mysql删除索引_MySQL 索引详解
  11. 谁抢光了你的火车票?
  12. 关于神经网络的英语单词有,神经网络的英文单词
  13. BT5中安装VMWare Tool的相关命令
  14. 微信小程序如何实现转发/分享功能
  15. bugzilla perl mysql apache windows,windows下配置bugzilla
  16. 巴塞尔iii_巴塞尔协议——银行风控实施的超级系统工程 之二
  17. 【类型初始值设定项引发异常】问题解决
  18. Linux系统 查看 Vendor id 和Device id
  19. Springboot整合JdbcTemplate实现分页查询
  20. 【问题解决】“Web“ facet resources

热门文章

  1. sqlserver 2008r2 表分区拆分问题
  2. [转] [翻译]C# Object Initialization[完整版]
  3. 欢迎参与Java 事务讨论
  4. 温故(2):pass by value
  5. 高通平台android7.1系统显示旋转180度
  6. android recovery 模块知识需求汇总
  7. hdu 5511 Minimum Cut-Cut——分类讨论思想+线段树合并
  8. 深入浅出浏览器渲染原理
  9. kvm.huge页、常用命令和桥接设置
  10. 开源助推进NFV发展,红帽为运营商“定制”NFV落地方案