当前位置:网站首页>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文件)

二、编写代码的思路

整个过程主要分为三步:

  1. 遍历整个hex文件,找出最小地址和最大地址(也就是起始地址和结束地址),算出数据长度(数据长度=结束地址-起始地址+1),根据得到的数据长度,分配对应大小的内存(开辟一个数组);

  2. 再次遍历整个hex文件,计算每条数据记录中的起始地址与hex文件起始地址的偏移量,按照偏移量将该条数据记录中的数据部分写入第一步的数组中。(这样就实现了按照从低到高的地址顺序排列整个hex文件的数据)。

  3. 最后只需要将该数组写出到文件中即可。

三、代码实现【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

原网站

版权声明
本文为[明如正午]所创,转载请带上原文链接,感谢
https://star-302.blog.csdn.net/article/details/126248276