在了解hex文件格式的基础上阅读本文更佳。可阅读下边文章:
【HEX文件格式详解】https://star-302.blog.csdn.net/article/details/119563635
将hex文件的内容转成按地址顺序(从低到高)排列的二进制数据(bin文件)
整个过程主要分为三步:
遍历整个hex文件,找出最小地址和最大地址(也就是起始地址和结束地址),算出数据长度(数据长度=结束地址-起始地址+1),根据得到的数据长度,分配对应大小的内存(开辟一个数组);
再次遍历整个hex文件,计算每条数据记录中的起始地址与hex文件起始地址的偏移量,按照偏移量将该条数据记录中的数据部分写入第一步的数组中。(这样就实现了按照从低到高的地址顺序排列整个hex文件的数据)。
最后只需要将该数组写出到文件中即可。

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";//最后一行的数据长度
///
/// 【第1步】获取hex文件的起始和终止地址,并获取其字节长度
///
///
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();
}
///
///【第2步】填充数组内容
///
/// hex文件路径
/// 填充的字节数组
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;
}
}
}
///
/// 【第3步】将数组写到bin文件
///
/// 新建bin文件的路径
/// 写入的字节数组
/// 开始索引
/// 写入的字节长度
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();
}
///
/// 16进制字符串 转化为数值
///
/// 16进制字符串
///
private int Convert2Hex(string content)
{
return Convert.ToInt32(content, 16);
}
}
}

链接: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