当前位置:网站首页>C#【必备技能篇】Hex文件转bin文件的代码实现
C#【必备技能篇】Hex文件转bin文件的代码实现
2022-08-10 21:02:00 【明如正午】
引言
在了解hex文件格式的基础上阅读本文更佳。可阅读下边文章:
【HEX文件格式详解】https://star-302.blog.csdn.net/article/details/119563635
一、需求
将hex文件的内容转成按地址顺序(从低到高)排列的二进制数据(bin文件)
二、编写代码的思路
整个过程主要分为三步:
遍历整个hex文件,找出最小地址和最大地址(也就是起始地址和结束地址),算出数据长度(数据长度=结束地址-起始地址+1),根据得到的数据长度,分配对应大小的内存(开辟一个数组);
再次遍历整个hex文件,计算每条数据记录中的起始地址与hex文件起始地址的偏移量,按照偏移量将该条数据记录中的数据部分写入第一步的数组中。(这样就实现了按照从低到高的地址顺序排列整个hex文件的数据)。
最后只需要将该数组写出到文件中即可。
三、代码实现【C#】
using System;
using System.Globalization;
using System.IO;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
/* 说明: 1.hex内容读取规则示例: OxO-Ox500【所有字节内容都有】 0x0-0x100,0x300-Ox500 【中间有部分地址内容缺失,根据实际情况默认填充Ox00/OxFF】 2.扩展地址分区也可刷写【重点!!!】:hex文件地址分区的话(segment),此代码也可以通过 */
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public static string hexFilePath = null;//选择的hex文件路径
public static string binFilePath = null;//保存的bin文件路径
private void btn_OpenFile_Click(object sender, EventArgs e)
{
OpenFileDialog open = new OpenFileDialog();
open.RestoreDirectory = true;
//open.Filter = "File(*.hex,*.s19)|*.hex;*.s19|BIN File(*.bin)|*.bin";
open.Filter = "File(*.hex)|*.hex";
open.InitialDirectory = Directory.GetCurrentDirectory();
if (DialogResult.OK == open.ShowDialog())
{
hexFilePath = txt_HexFile.Text = open.FileName;
binFilePath = open.FileName.Replace(".hex", ".bin");//确定生成的bin文件路径
}
}
private void btn_StartConvert_Click(object sender, EventArgs e)
{
try
{
//【01】获取hex文件的起始和终止地址(Lowest_Address和Highest_Address) ,并获取其字节长度(dataLength)
GetAddress(hexFilePath);
byte[] buffer = new byte[dataLength]; //创建和hex文件对应长度的字节数组
//【02】填充数组内容
//(情形1:所有地址内容都在hex文件中;情形2:在hex文件中有些地址内容缺失,需要填充默认值“0x00”或“0xFF”)
FillData(hexFilePath, ref buffer);
//【03】将数组写到bin文件
WritetoBinFile(binFilePath, buffer, 0, dataLength);
MessageBox.Show("转换成功");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public static int startAddress = 0;//解析的起始地址
public static int endAddress = 0;//解析的终止地址
public static int dataLength = 0;//字节总长度=endAddress-startAddress+1
public static string startExtendedAddress = "0000";//第一个扩展地址
public static string endExtendedAddress = "0000";//最后一个扩展地址
public static bool isFirstExtendedAddress = true;//是否是第一次检测到“0x04”
public static string startDataAddress = "0000";//第一个数据地址【对应startExtendedAddress】
public static string endDataAddress = "0000";//最后一个数据地址【对应endExtendedAddress】
public static bool isFirstDataAddress = true;//是否是第一次检测到“0x00”
public static string lastDataLength = "00";//最后一行的数据长度
/// <summary>
/// 【第1步】获取hex文件的起始和终止地址,并获取其字节长度
/// </summary>
/// <param name="hexPath"></param>
private void GetAddress(string hexPath)
{
FileStream fsRead = new FileStream(hexPath, FileMode.OpenOrCreate, FileAccess.Read);
StreamReader HexReader = new StreamReader(fsRead); //读取数据流
while (true)
{
string currentLineData = HexReader.ReadLine(); //读取Hex中一行
if (currentLineData == null) {
break; } //读取完毕,退出
if (currentLineData.Substring(0, 1) == ":") //判断首字符是”:”
{
if (currentLineData.Substring(1, 8) == "00000001")
{
if (endExtendedAddress == "0000")
{
endAddress = Convert2Hex(startExtendedAddress + endDataAddress) + Convert2Hex(lastDataLength) - 1;//获得终止地址
dataLength = endAddress - startAddress + 1;
}
else
{
endAddress = Convert2Hex(endExtendedAddress + endDataAddress) + Convert2Hex(lastDataLength) - 1;//获得终止地址
dataLength = endAddress - startAddress + 1;
}
break;
} //文件结束标识
string type = currentLineData.Substring(7, 2);
switch (type)
{
case "04":
if (isFirstExtendedAddress)
{
startExtendedAddress = currentLineData.Substring(9, 4);
isFirstExtendedAddress = false;
}
else
{
endExtendedAddress = currentLineData.Substring(9, 4);
}
break;
case "00":
if (isFirstDataAddress)
{
startDataAddress = currentLineData.Substring(3, 4);
startAddress = Convert2Hex(startExtendedAddress + startDataAddress);//获得起始地址
isFirstDataAddress = false;
}
else
{
endDataAddress = currentLineData.Substring(3, 4);
lastDataLength = currentLineData.Substring(1, 2);//为了获取最后一行的字节长度
}
break;
default:
break;
}
}
}
HexReader.Close();
fsRead.Close();
}
/// <summary>
///【第2步】填充数组内容
/// </summary>
/// <param name="hexPath">hex文件路径</param>
/// <param name="buffer">填充的字节数组</param>
private void FillData(string hexPath, ref byte[] buffer)
{
int lastLine_EndAddress_Real = startAddress;//上一行结束的真实地址【扩展地址+数据地址】,初始值为hex文件的起始地址
int currentLine_StartAddress_Real = 0;//下一行开始的真实地址【扩展地址+数据地址】
string currentExtendedAddress = "0000";//当前扩展地址
string currentLineDataAddress = "0000";//当前数据地址
int current_BufferIndex = 0;
FileStream fsRead = new FileStream(hexPath, FileMode.OpenOrCreate, FileAccess.Read);
StreamReader HexReader = new StreamReader(fsRead); //读取数据流
while (true)
{
string currentLineData = HexReader.ReadLine(); //读取Hex中一行
if (currentLineData == null) {
break; } //读取完毕,退出
if (currentLineData.Substring(0, 1) == ":") //判断首字符是”:”
{
//文件结束标识
if (currentLineData.Substring(1, 8) == "00000001")
{
break;
}
string type = currentLineData.Substring(7, 2);//读取当前行的类型
switch (type)
{
case "04":
currentExtendedAddress = currentLineData.Substring(9, 4);
break;
case "00":
currentLineDataAddress = currentLineData.Substring(3, 4);//当前数据地址
currentLine_StartAddress_Real = Convert2Hex(currentExtendedAddress + currentLineDataAddress);//实际开始地址值
//如果这一次的起始地址不等于上一次结束的下一个地址,则填充"0x00"
if (currentLine_StartAddress_Real != lastLine_EndAddress_Real)
{
for (int i = 0; i < currentLine_StartAddress_Real - lastLine_EndAddress_Real; i++) // 补空位置
{
byte value = byte.Parse("00", NumberStyles.HexNumber);
buffer[current_BufferIndex] = value;
current_BufferIndex++;
}
}
int currentLine_DataLength = Convert2Hex(currentLineData.Substring(1, 2));//获取当前行的数据长度
for (int i = 0; i < currentLine_DataLength; i++)
{
byte value = byte.Parse(currentLineData.Substring(i * 2 + 9, 2), NumberStyles.HexNumber);
buffer[current_BufferIndex] = value;
current_BufferIndex++;
}
lastLine_EndAddress_Real = currentLine_StartAddress_Real + currentLine_DataLength;
break;
default:
break;
}
}
}
//关闭Stream和文件
HexReader.Close();
fsRead.Close();
//hex文件最后没有的byte填充“00”
if (buffer.Length > current_BufferIndex)
{
for (int i = 0; i < buffer.Length - current_BufferIndex; i++)
{
byte value = byte.Parse("FF", NumberStyles.HexNumber);
buffer[current_BufferIndex + i] = value;
}
}
}
/// <summary>
/// 【第3步】将数组写到bin文件
/// </summary>
/// <param name="binPath">新建bin文件的路径</param>
/// <param name="buffer">写入的字节数组</param>
/// <param name="startIndex">开始索引</param>
/// <param name="length">写入的字节长度</param>
private void WritetoBinFile(string binPath, byte[] buffer, int startIndex, int length)
{
FileStream fsWrite = new FileStream(binPath, FileMode.Create, FileAccess.Write);//如果已存在相同文件名的文件,则删掉之前的,创建新的文件!!!
fsWrite.Write(buffer, startIndex, length);
fsWrite.Close();
}
/// <summary>
/// 16进制字符串 转化为数值
/// </summary>
/// <param name="content">16进制字符串</param>
/// <returns></returns>
private int Convert2Hex(string content)
{
return Convert.ToInt32(content, 16);
}
}
}
测试用的hex文件
链接:https://pan.baidu.com/s/1p1aciL2108ABdZcTqZhXew
提取码:0t67
Test1_noSegment.hex说明:
Test1_noSegment.hex和Test2_haveSegment.hex对比:
参考:https://blog.csdn.net/ZF_C_CQUPT/article/details/52676716
边栏推荐
猜你喜欢
化学制品制造业数智化供应链管理系统:建立端到端供应链采购一体化平台
【vulhub】MySql身份认证绕过漏洞复现(CVE-2012-2122)
ansible各个模块的详解和使用
【PCBA方案】电子握力测试仪方案she‘ji
Rider调试ASP.NET Core时报thread not gc-safe的解决方法
图扑智慧电力可视化大屏,赋能虚拟电厂精准减碳
力扣221题,最大正方形
Live Classroom System 09--Tencent Cloud VOD Management Module (1)
【nvm】【node多版本管理工具】使用说明和踩坑(exit status 1)
社区分享|货拉拉通过JumpServer纳管大规模云上资产
随机推荐
基于Pix4Dmapper的运动结构恢复法无人机影像三维模型重建
LeetCode-498-对角线遍历
快消品行业经销商协同系统:实现经销商可视化管理,提高沟通执行效率
The use of TortoiseSVN little turtle
关于 NFT 版权保护的争议
ACM模板笔记:八数码问题——使用BFS+康托展开打表解决
【一致性hash】负载均衡器分发请求
睡前故事|用Bitmap与AST做一个配置化时长系统
svg+元素js实现在图片上描点成框,并获取相对图片的坐标位置
APP application related instructions in Auto.js
LeetCode-36-二叉搜索树与双向链表
2022.8.8好题选讲(数论场)
流程控制结构——《mysql 从入门到内卷再到入土》
npm‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件
Uniapp编译后小程序的代码反编译一些思路
C. Rotation Matching
使用SylixOS虚拟串口,实现系统串口自由
CGO 初步认知和基本数据类型转换
Introduction to PostgreSQL
找的笔试题的复盘(一)