Hex文件格式解析及读写修改代码实现

Hex文件每一行数据全部由十六进制数字组成,包含 :、数据长度、起始地址、记录类型、数据、校验和六个部分。

hex 文件解析java hex文件内容_数据

上图中,每一行记录都以“:”开头,“20”为后面的数据长度,表示该记录有32字节的数据,“C240”为该行记录的起始地址中的低位,后面的“00”为该记录的类型,

“0060FAE83132333435363738393000000060C2000060FFF7000900020060FFF8”为该记录所包含的全部32字节数据,“B5”为校验和,

此行就是将数据依次刷写到起始地址为“0060C240”的连续地址中,后面会解释“0060”的由来。

每字节数据被编码成2个16进制字符,第一个字符代表数据的高四位,第二个字符代表数据的低4位。

 

1. 记录类型

Hex文件记录类型包括00、01、02、03、04、05等,每一种都包含不同的含义

00:数据记录

01:文件结束记录

02:扩展段地址记录

03:开始段地址记录

04:扩展线性地址记录

05:开始线性地址记录

hex 文件解析java hex文件内容_数据_02

上图中截取了三种记录类型04、00和01

第一行中数据长度为02,表示两字节的数据“095B”,04位扩展线性数据记录,扩展地址就是04记录中的数据位“095B”,

该地址就作为一下每行的起始地址中的高位,第二行记录中的地址“0000”为低位,那么第二行记录的起始地址就是“095B0000”,

第三行记录的起始地址就是“095B0020”,“095B”会一直作为高位,直到下一个扩展线性记录的出现,

最后一行为文件记录的结束

 

2. 起始地址

起始地址一般由高位和低位组成,即04记录中的地址加上00记录中的地址

 

3. 数据长度

包含一个字节,即后面数据的字节数的十六进制表示

 

4.校验和

包含一个字节,校验和=0xFF&(0x100-(长度字节+地址字节+类型字节+数据字节))

hex 文件解析java hex文件内容_数据_03

 

 

长度字节+地址字节+类型字节+数据字节=0x20+0x00+0x00+0x00+0x00+...+0xC3+0xC3=0x1880

0x80=0xFF&(0x100-0x1880)

 

5.实现代码

hex 文件解析java hex文件内容_数据_04

hex 文件解析java hex文件内容_补全_05

1 public class Hex
  2     {
  3         public string path;                                                        //选择文件的路径
  4         public List<List<string>> listAllline = new List<List<string>>();          //依据区域对数据进行存储,一个扩展性地址放一个list中,存储含有部分记录的Hex文件包括(00、04和01的记录等)
  5 
  6 
  7         /// <summary>
  8         /// 读取Hex文件,将所有记录存储在List中,便于调用修改
  9         /// </summary>
 10         /// <param name="file_path"></param>
 11         /// <returns></returns>
 12         public bool Read_Hex(string file_path)
 13         {
 14             FileStream fileStream = null ;
 15             StreamReader streamReader = null;
 16             int count = 0;
 17             string type;
 18             int regionNum = -1;
 19             try
 20             {
 21                 fileStream = new FileStream(file_path, FileMode.Open, FileAccess.Read);
 22                 streamReader = new StreamReader(fileStream, Encoding.Default );
 23                 string currentLine = "";
 24                 listAllline.Clear();
 25 
 26                 while ((currentLine = streamReader.ReadLine()) != null && currentLine.Trim ()!="")
 27                 {
 28                     if(currentLine.Substring(0, 1)==":")
 29                     {
 30                         type = currentLine.Substring(7, 2);
 31                         if (type == "04" || type == "01")
 32                         {
 33                             regionNum++;
 34                             listAllline.Add(new List<string>());
 35                         }
 36                         count++;
 37                         listAllline[regionNum].Add(currentLine);
 38                     }
 39 
 40                 }
 41                 Console.WriteLine("文件中共有" + count + "行数据");                
 42                 Console.WriteLine( regionNum  + "块区域");
 43                 return true;
 44             }
 45             catch (Exception ex)
 46             {
 47                 Console.WriteLine(ex.ToString() + count);
 48                 MessageBox.Show(ex.Message +count.ToString());
 49                 return false;
 50             }
 51             finally
 52             {
 53                 fileStream.Close();
 54                 streamReader.Close();
 55             }
 56 
 57         }
 58 
 59         /// <summary>
 60         /// 计算一行数据的校验和
 61         /// </summary>
 62         /// <param name="line">包含:的整行记录 </param>
 63         /// <returns></returns>
 64         private string Checksum(string line)
 65         {
 66             string checkSum ;
 67             int sum = 0;
 68             string[] byteNum = new string[line.Length / 2 ];//计算字节数
 69             for (int i = 1; i < line.Length / 2 ; i++)
 70             {
 71                 byteNum[i] = line.Substring(i * 2 + 1, 2);//从长度位将一行数据按照字节分割为字节数组,注意前面的:
 72                 sum += Convert.ToInt32(byteNum[i], 16);//将数据进行累加
 73             }
 74             checkSum = Convert.ToString(0xFF & (0x100-sum), 16); //计算校验位
 75             return checkSum;
 76         }
 77 
 78         /// <summary>
 79         /// 将区域内不连续的地址补全
 80         /// </summary>
 81         /// <param name="completeValue">用于补全的字符</param>
 82         /// <returns></returns>
 83         public List<List<string>> CompleteFile(string completeValue)
 84         {
 85             List<List<string>> listTemp = new List<List<string>>();//暂存数据
 86             List<List<string>> listCompletion = new List<List<string>>();//用来存储补全后的数据
 87             uint currentAdd = 0;
 88             uint dataLength = 0;
 89             uint lastDataLength = 0;                                 //上一行数据长度
 90             uint lastAdd = 0;                                        //上一行地址
 91             int completeLine = 0;                                    //计算区域补全的行数
 92             int totalComplete = 0;                                   //计算总补全的行数
 93             string lastLine=string.Empty  ;                          //上一行的记录
 94             string currentLine;
 95 
 96             try
 97             {
 98                 #region 将地址相同高位的记录放入一个list中
 99                 int a = -1;
100                 for (int i = 0; i < listAllline.Count; i++)
101                 {
102                     a++;
103                     listTemp.Add(new List<string>());
104                     string firstLine = listAllline[i][0];
105                     for (int k = 0; k < listAllline[i].Count; k++)
106                     {
107                         listTemp[a].Add(listAllline[i][k]);
108                     }
109                     for (int j = i+1; j < listAllline.Count; j++)
110                     {
111                         if (firstLine == listAllline[j][0])
112                         {
113                             for (int k = 1; k < listAllline[j].Count; k++)
114                             {
115                                 listTemp[a].Add(listAllline[j][k]);
116                             }
117                             i++;
118                         }
119                     }
120                 }
121                 #endregion
122                 StringBuilder temp = new StringBuilder();
123                 for (int i = 0; i < listTemp.Count; i++)
124                 {
125                     completeLine = 0;
126                     listCompletion.Add(new List<string>());
127                     for (int j = 0; j < listTemp[i].Count; j++)
128                     {
129                         currentLine = listTemp[i][j];
130                         if (j == 0)
131                         {
132                             listCompletion[i].Add(currentLine);
133                             continue;
134                         }
135                         if (j == 1)
136                         {
137                             if(currentLine.Substring(3, 4)=="0000")//第一行的地址低位就是0000
138                             {
139                                 listCompletion[i].Add(currentLine);
140                                 lastLine = currentLine;
141                                 lastDataLength = Convert.ToUInt32(currentLine.Substring(1, 2), 16);
142                                 lastAdd = Convert.ToUInt32(currentLine.Substring(3, 4), 16);
143                                 continue;
144                             }
145                             else        //第一行的地址低位不是0000,从头开始做补全
146                             {
147                                 temp.Clear();
148                                 completeLine++;
149                                 temp.Clear();
150                                 temp.Append(currentLine.Substring(0, 3));
151                                 string newAdd_string = "0000";
152                                 temp.Append(newAdd_string);
153                                 for (int k = 0; k < Convert.ToInt32(currentLine.Substring(1, 2),16); k++)
154                                 {
155                                     temp.Append(completeValue);
156                                 }
157                                 temp.Append(Checksum(temp.ToString()));
158                                 listCompletion[i].Add(temp.ToString());
159 
160                                 lastLine = temp.ToString ();
161                                 lastDataLength = Convert.ToUInt32(lastLine.Substring(1, 2), 16);
162                                 lastAdd = Convert.ToUInt32(lastLine.Substring(3, 4), 16);
163                             }
164                         }                        
165 
166                         dataLength = Convert.ToUInt32(currentLine.Substring(1, 2), 16);
167                         currentAdd = Convert.ToUInt32(currentLine.Substring(3, 4), 16);
168 
169                         if (lastAdd + lastDataLength < currentAdd)          //判断相邻记录地址是否连续
170                         {
171                             int completeLen = Convert.ToInt32(currentAdd - lastAdd - lastDataLength);    //计算需要补全的长度
172                             uint newAdd = lastAdd;                                      //每行新记录填补的地址
173                             temp.Clear();
174                             while (completeLen > 0)
175                             {
176                                 if (completeLen <= lastDataLength)               //需要补的数据长度不足上一行记录的数据长度
177                                 {
178                                     completeLine++;
179                                     temp.Clear();
180                                     temp.Append(":");
181                                     string newLen = Convert.ToString(completeLen, 16).PadLeft(2, '0').ToUpper();
182                                     temp.Append(newLen);
183                                     string newAdd_string = Convert.ToString(newAdd + completeLen, 16).PadLeft(4, '0').ToUpper();
184                                     temp.Append(newAdd_string);
185                                     for (int k = 0; k < completeLen; k++)
186                                     {
187                                         temp.Append(completeValue);
188                                     }
189                                     temp.Append(Checksum(temp.ToString()));
190                                     listCompletion[i].Add(temp.ToString());
191                                     completeLen -= completeLen;                  //减去已补过的长度
192                                 }
193                                 else
194                                 {
195                                     completeLine++;
196                                     temp.Clear();
197                                     temp.Append(lastLine.Substring(0, 3));
198                                     string newAdd_string = Convert.ToString(newAdd + lastDataLength, 16).PadLeft(4, '0').ToUpper();
199                                     temp.Append(newAdd_string);
200                                     for (int k = 0; k < Convert.ToInt32(lastDataLength); k++)
201                                     {
202                                         temp.Append(completeValue);
203                                     }
204                                     temp.Append(Checksum(temp.ToString()));
205                                     listCompletion[i].Add(temp.ToString());
206                                     completeLen -= Convert.ToInt32(lastDataLength);
207                                 }
208                                 newAdd = newAdd + lastDataLength;
209                             }
210 
211                             currentAdd = newAdd + lastDataLength;                               //当前行的地址
212                             listCompletion[i].Add(currentLine);
213                         }
214                         else
215                         {
216                             listCompletion[i].Add(currentLine);                        
217                         }
218                         lastAdd = currentAdd;                                            //记录上一行地址
219                         lastDataLength = dataLength;                                     //记录上一行数据长度
220                         lastLine = currentLine;
221 
222                         if (j == listTemp[i].Count-1)                                 //判断是否到这个list的最后一行   
223                         {
224                             if ((j+ completeLine) < 2048)                             //一个区域最多有2048行记录,
225                             {
226                                 temp.Clear();
227                                 uint newAdd = lastAdd;
228                                 while ((j + completeLine) < 2048)                     //开始末尾补全
229                                 {
230                                     completeLine++;
231                                     temp.Clear();
232                                     temp.Append(lastLine.Substring(0, 3));
233                                     string newAdd_string = Convert.ToString(newAdd + lastDataLength, 16).PadLeft(4, '0').ToUpper();
234                                     temp.Append(newAdd_string);
235                                     for (int k = 0; k < Convert.ToInt32(lastDataLength); k++)
236                                     {
237                                         temp.Append(completeValue);
238                                     }
239                                     temp.Append(Checksum(temp.ToString()));
240                                     listCompletion[i].Add(temp.ToString());
241                                     newAdd = newAdd + lastDataLength;
242                                     
243                                 }
244                             }                         
245                         }
246                     }
247                     totalComplete += completeLine;
248                 }
249 
250                 Console.WriteLine("共补全了" + totalComplete + "行");
251                 return listCompletion;
252             }
253             catch(Exception ex)
254             {
255                 Console.WriteLine(ex.Message );
256                 MessageBox.Show(ex.ToString ());
257                 return null;
258             }
259             
260         }
261 
262         /// <summary>
263         /// 检查每行记录数据是否有缺失,是否完整
264         /// </summary>
265         /// <returns></returns>
266         public bool CompleteCheck(string line)
267         {
268             string type = line.Substring(7,2);
269             string length = line.Substring(1,2);
270             string address = line.Substring(3,4);
271             return line.Length == 1 + 2 + 4 + 2 + Convert.ToInt32(length) * 2 + 2 ? true : false;
272         }
273 
274         /// <summary>
275         /// 依据地址和数据修改Hex文件
276         /// </summary>
277         /// <param name="startAdd"></param>
278         /// <param name="modifyStr"></param>
279         /// <returns></returns>
280         public bool Modify_hex(string startAdd, string modifyStr)
281         {
282             try
283             {
284                 List<int> goalRegionList = new List<int>();            //存储具有地址高位的记录区域
285                 int modifyLen = modifyStr.Length;                      //修改的数据长度,判断修改是否完成
286                 string add_High = startAdd.Substring(0, 4);
287                 string add_Low = startAdd.Substring(4, 4);
288                 for (int i = 0; i < listAllline.Count; i++)
289                 {
290                     if (add_High == listAllline[i][0])
291                     {
292                         goalRegionList.Add(i);
293                     }
294                 }
295 
296                 uint add_Low_uint = Convert.ToUInt32(add_Low, 16);
297                 string currentLine = string.Empty;
298                 uint currentAdd_Low_unit;
299                 for (int k = 0; k < goalRegionList.Count; k++)
300                 {
301                     for (int i = 1; i < listAllline[goalRegionList[k]].Count; i++)
302                     {
303                         currentLine = listAllline[goalRegionList[k]][i];
304                         if (currentLine.Length <= 11)                       //跳过01的记录
305                         {
306                             continue;
307                         }
308                         currentAdd_Low_unit = Convert.ToUInt32(currentLine.Substring(3, 4), 16);
309                         if (add_Low_uint >= currentAdd_Low_unit && Convert.ToUInt32(add_Low_uint - currentAdd_Low_unit) < Convert.ToUInt32(currentLine.Substring(1, 2), 16))//找到需要修改的数据的起始地址所在行
310                         {
311                             while (modifyLen > 0)
312                             {
313                                 currentAdd_Low_unit = Convert.ToUInt32(currentLine.Substring(3, 4), 16);
314                                 int differenceAdd = Convert.ToInt32(add_Low_uint - currentAdd_Low_unit);          //一行中需修改的起始地址之前的数据地址
315                                 int modifyAdd = Convert.ToInt32(currentLine.Substring(3, 4), 16) * 2 - differenceAdd * 2;//每行中需要修改的数据长度
316 
317                                 if (Convert.ToInt32(currentLine.Substring(3, 4), 16) - differenceAdd >= modifyLen / 2)//判断需要修改的数据地址是不是在同一行
318                                 {
319                                     string str1 = currentLine.Remove(9 + (differenceAdd) * 2, modifyLen);//从修改的起始地址位置开始移除旧数据,长度为需要修改的数据长度,12 = 类型2字符+长度2字符+地址8字符
320                                     string str2 = str1.Insert(9 + (differenceAdd) * 2, modifyStr);//将新数据插入当前记录行
321                                     string sum_string = Checksum(str2.Remove(str2.Length - 2));//计算新的校验位字节
322                                     currentLine = str2.Remove(str2.Length - 2, 2) + sum_string;//移除旧校验位,加入新校验位
323                                     modifyLen = modifyLen - modifyAdd;//正常情况下,修改的数据地址在同一行,此时计算之后modifyLen=0,跳出循环
324                                 }
325                                 else                 //地址不在同一行
326                                 {
327                                     string str1 = currentLine.Remove(9 + (differenceAdd) * 2, Convert.ToInt32(currentLine.Substring(1, 2), 16) * 2 - differenceAdd * 2);//移除地址后面的所有数据和校验位
328                                     string str2 = str1.Insert(9 + (differenceAdd) * 2, modifyStr.Substring(0, (Convert.ToInt32(currentLine.Substring(1, 2), 16) - (differenceAdd)) * 2));//加入新数据
329                                     string sum_string = Checksum(str2.Remove(str2.Length - 2));
330                                     currentLine = str2.Remove(str2.Length - 2, 2) + sum_string;
331                                     modifyLen = modifyLen - modifyAdd;//计算剩余需要修改的数据长度
332                                     modifyStr = modifyStr.Remove(0, modifyAdd);//移除已经修改的数据
333                                     startAdd = startAdd + (Convert.ToUInt32(currentLine.Substring(1, 2), 16) - Convert.ToUInt32(differenceAdd));//计算剩余数据的起始地址
334                                 }
335                             }
336                         }
337                     }
338                 }
339                 
340                 return true;
341             }
342             catch(Exception ex)
343             {
344                 Console.WriteLine(ex.Message);
345                 return false;
346             }
347         }
348 
349         /// <summary>
350         /// 生成新的Hex文件
351         /// </summary>
352         /// <param name="newFilepath"></param>
353         /// <returns></returns>
354         public bool Write_Hex(string newFilepath)
355         {
356             StreamWriter Stream_Writer = null;
357             try
358             {
359                 Stream_Writer = new StreamWriter(newFilepath + ".hex", false);
360                 for (int i = 0; i < listAllline.Count; i++)
361                 {
362                     for (int j = 0; j < listAllline[i].Count; j++)
363                     {
364                         Stream_Writer.WriteLine(listAllline[i][j]);
365                     }
366                 }
367                 return true;
368             }
369             catch(Exception ex)
370             {
371                 Console.WriteLine(ex.Message );
372                 return false;
373             }
374             finally
375             {
376                 Stream_Writer.Close();
377             }
378         }

View Code

 

如有错误,欢迎指正