如何解析二进制文件中的文本数据

How to parse text data from a binary file

您好,我有一个包含大量资源的二进制文件,我想使用 C# 查找并解析此文件中的 ASCII 文本对象,如下所示

之前有很多二进制垃圾

ONMAP 0 131072 "description " 0 "name" "FLAG" "FLAG" 7900.000000 0.000000 1499.999268 2.000000 6.000000 8.000000 1.000000 1.000000 1.000000 0 0 0 -1 1 0 0 -1 0.101900 2 36 255 后跟一个换行符

这些对象之后有很多二进制垃圾

这里每个对象都以它的标签ONMAP开头,值用白色分隔space,字符串用双引号括起来,必须按照写入的顺序读取,我们不知道数据在哪里在文件中所以我想搜索二进制文件直到找到 onmap 并将属性读入列表但是一旦发现 onmap 我不知道如何解析属性。

有一个标准的 Unix 程序可以完全满足您的需求:strings

您可以在 Gnu binutils 下找到源代码:

http://www.gnu.org/software/binutils/

程序比较小,比较简单。它使用的 "algorithms" 直接适用于 C#(或者等效地适用于 Java 或 C++)。

我强烈建议通过获取将包含指向字符串开头的点的文件格式来定位字符串的开头。下面的代码在大多数情况下都可以工作,但不能保证。 Gnu 实用程序基本上做同样的事情。像这样的实用程序只能用作快速解决方案。二进制数据是伪随机的,5 个字符的匹配是可能的,但非常遥远。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        enum State
        {
            FIND_ONMAP,
            FIND_RETURN,
            DONE
        }

        const string FILENAME = @"c:\temp\test.txt";
        static void Main(string[] args)
        {
            List<byte> onmap = Encoding.UTF8.GetBytes("ONMAP").ToList();

            FileStream stream = File.OpenRead(FILENAME);
            int data = 0;
            State state = State.FIND_ONMAP;
            List<byte> buffer = new List<byte>();
            while ((data = stream.ReadByte()) != -1)
            {
                switch (state)
                {
                    case State.FIND_ONMAP:
                        if (buffer.Count < 5)
                        {
                            buffer.Add((byte)(data & 0xff));
                        }
                        else
                        {
                            buffer.RemoveAt(0);
                            buffer.Add((byte)(data & 0xff));
                        }
                        if (buffer.SequenceEqual(onmap))
                        {
                            state = State.FIND_RETURN;
                        }
                        break;
                    case State.FIND_RETURN:
                        if (data == 10)
                        {
                            state = State.DONE;
                            break;
                        }
                        else
                        {
                            buffer.Add((byte)(data & 0xff));
                        }
                        break;

                }
                if (state == State.DONE) break;

            }


            if (state == State.DONE)
            {
                string results = Encoding.UTF8.GetString(buffer.ToArray());
                Console.WriteLine(results);
                Console.ReadLine();
            }

        }
    }
}
​