2

我正在做一个项目,我从文件中读取数据,我需要操作其中的一些数据。

数据是二进制的,其中包含一些 ASCII 编码文本。如果这很重要,数据也会保存在 Big Endian 中。

我想要完成的是在这些数据中找到一个模式并操作该模式的一部分。

示例:(09 49 6E 76 65 6E 74 6F 72 79 0A 00 00 00 02 01 00)

这表示 Inventory 中有多少个字母的数字 9,后跟不带引号的 ASCII“Inventory”。“0A”标记该 ASCII 文本的结尾,后跟 00 00 00 02 标记我们库存的大小“2”。“01 00” 标志着整个库存区域的结束。

示例 2:(04 53 6C 6F 74 00 02 00)

这表示 Slot 中有多少个字母的数字 4,后跟不带引号的 ASCII“Slot”。“00”是 ASCII 文本和插槽号“02”之间的空格,后跟区域“00”的结尾。

我需要在文件中找到这些模式和其他几个模式。然后我需要修改部分模式并写入磁盘。

ExampleModify: (04 53 6C 6F 74 00 02 00) "From above" to (04 53 6C 6F 74 00 07 00) 改变 "slot number '02' to '07'.

另一个需要注意的是,虽然我需要在文件中搜索不同大小、长度和包含的数据的多个模式,但这些模式的多个部分可能包含需要单独修改的不同数据作为一个整体。

澄清:(库存,插槽,id,计数) - 将被视为一个人的信息。

记录的每个人都可以有多个(Inventory、Slot、id、Count)副本。

我想向用户显示此信息,并为他们提供修改组中每个元素的选项。

我不是一个好的程序员,想学习,如果你有例子我很感激,如果你有建议,请给它。如果你能把它调低就更好了,谢谢。我现在有一个正在进行的工作,但我现在卡住了。如果你想看看我有什么,请告诉我。

我所拥有的总结:将文件读入 byte[] 然后将整个数组显示到控制台。就是这样。带有一些格式化和一些调试信息,用于定位我读入数组的那个块。

这是我在 pastebin 上的代码的链接。关联

我意识到我没有得到 (Inventory, Slot, id, Count) 的所有出现,我也需要修复它。

编辑:示例(09 49 6E 76 65 6E 74 6F 72 79 0A 00 00 00 02 01 00)这是我正在读取的文件中固定长度的二进制数据块。如前所述,09 表示字符串的长度。字符串后面是 (0A 00 00 00 02 01 00) 的重要部分是 (02) 这是因为这是二进制数据片中唯一改变的字节。“02”表示“2”,表示该特定人员记录有 2 个 (Slot, id, Count) 实例。

(File)
    (09 Inventory 0A 00 00 00 02 01 00) // Start of person 1's record with 2 instances.
        (Slot)
        (id)
        (Count)
        (Slot)
        (id)
        (Count)
    (Rotation)  // End of person 1's record

    (09 Inventory 0A 00 00 00 04 01 00) // Start of person 2's record with 4 instances.
        (Slot)
        (id)
        (Count)
        (Slot)
        (id)
        (Count)
        (Slot)
        (id)
        (Count)
        (Slot)
        (id)
        (Count)
    (Rotation)  // End of person 2's record
(File End)

这个想法是我想编辑“id”或通过添加到库存中来增加插槽的数量并添加更多的(Slot,id,Count)实例。

“id” - 包含项目 ID

“Slot” - 包含库存槽编号

“计数” - 包含该插槽中有多少项目。编辑注意:如果我不清楚,请告诉我,再次感谢。

4

2 回答 2

3

你说你不是一个好的程序员。然后我会提出一些基本的建议。

首先,对于任何问题,将其分解。尝试将其分解为您可以解决的更简单的子问题,或者认为会更容易解决。您说您想检查文件中的模式,然后可能会修改一些数据并将其写回。作为第一步,我想说这些是您需要解决的主要子问题才能获得完整的解决方案。

  • 读取文件
  • 在二进制数据中搜索模式
  • 进行修改
  • 写出修改后的数据。

您主要关注“搜索模式”部分,因此我将集中进一步评论。所有这些其他部分也可能很棘手,但您可以自己解决它们,或者在 stackoverflow 或其他地方寻找其他人如何解决它们的提示。

好的,现在,关于“搜索模式”。在我阅读你的描述时,

在我看来,字节数组中的第一个字节是文本长度。在 C# 代码中,可以像这样显式声明展示您的模式的数据数组:

byte[] data = new byte[] { 9, 0x49, 0x6E, 0x76, 0x65, 0x6E, 0x74,
               0x6F, 0x72, 0x79, 0x0A, 0, 0, 0, 2, 1, 0 } ;

当然,您不会明确声明数组。您将通过文件读取操作创建或填充数组。在这一点上,文件读取仍然是一个悬而未决的问题,但没关系 - 您可以单独解决它。而且,效果是一样的——当您成功读取文件时,您将拥有一个看起来像上面明确声明的数组的字节数组。

好的,现在你如何操作这些数据?第一个字节是字符串数据的长度。接下来的 N 个字节是字符串数据。然后你有一些其他的东西。

您没有准确描述要进行哪些“修改”,但是根据您提供的信息,应该很容易浏览数据。

如果您想获取数组中数据的“切片”,您可以这样做。

int length = (int) data[0];
byte[] s = new byte[length];
Array.Copy(data, 0, s, 0, length);
// now, s contains N bytes, representing the string

您可能想要做的下一件事是从您切出的那些字节中获取一个实际的字符串。为此,请使用Encoding 类

String word = System.Text.Encoding.UTF8.GetString(s);

我不理解字符串数据后面的数据模式。在某些情况下是00,在某些情况下是0A

但也许你知道模式。遵循相同的方式,您可以遍历一个“记录”的所有数据。当您到达记录的末尾时,请重新开始并处理下一个。进入下一个“记录”的关键是知道从你从文件中读取的数据中取出多大的数据片段。


这让我们回到了“读取文件”的子问题。从文件中获取适量数据的一种方法是只读取第一个字节,然后再读取文件中的 N 个字节。(参见System.IO.Stream.Read)。

byte[] size = new byte[1];
var fileStream = File.OpenRead(path);
int offset = 0;
int n;
n = fileStream.Read(size, offset, 1);
// size[0] now contains the byte of data indicating the number of bytes to follow

此时您可以读取接下来的 N 个字节:

int length = (int)size[0];
byte[] stringData = new byte[length];
n = fileStream.Read(stringData, offset, length);

现在你可以得到字符串了。

String word = System.Text.Encoding.UTF8.GetString(stringData);

...等等。读取所有尾随字节。此时,由fileStream指向文件中下一条记录的指针隐式持有的游标。

于 2012-07-07T21:44:31.230 回答
0

我同意@Cheeso 上面所说的,这是一个好的开始。我将描述一个替代解决方案:

  1. 为所有已知部分定义操作码(一个以 0x4 0x56 开头,一个以 0xA 0x2 开头,等等)。
  2. 读取内存中的文件。
  3. 对内存中的字节数组应用匹配算法并提取每个匹配模式的起始位置。出于性能原因,我建议使用一种众所周知的搜索算法(或其变体),例如Knuth-Morris-PrattBoyer-Moore
  4. 此时,您应该在应用程序中缓存您找到的所有模式的所有开始位置。您可以为此使用列表字典(其中键是模式类型),但您可以将其包含到自定义类(在文件中具有模式 id 和模式偏移量),然后只需使用列表并使用 LINQ 访问所有内容.
  5. 在需要时访问和解码实际模式,因此不要在读取文件后立即访问和解码。我想您对它们有不同的用途,并不是在有人加载文件后立即出现。

因此,这已经为您提供了文件中所有模式出现的列表。您可以使用它向用户显示某种列表。

我快速浏览了您的代码。它真的很大,都塞满了几个大功能。您需要对其进行一些结构化。每个任务需要一个类来加载和解析文件,然后是许多较小的函数。

当您在应用程序中使用模式时,例如当您让用户可以对其进行修改时,使用此机制应该相当容易:

  • 在您已经拥有的偏移量处读取数据。
  • 你知道偏移量,你也知道长度。当需要写回修改时,您可以将自己定位在加载流中的特定位置并覆盖。

必须不断地处理文件中的数据以进行各种修改,我会说最好将其保存在内存中并在需要时保存它,同时仍将修改后的版本保存在内存中。有时可能需要在内存缓存中更新模式偏移量,因此您可以仅将初始解析过程应用于文件的一小部分(以加快处理速度)。

如果您在加载文件后立即需要模式数据,那么您可以在第一次遍历文件时应用模式解码过程(当您提取偏移量时)。我建议仅将重要的内容保留在单独的集合中,以便向用户显示(例如仅 ID 和您需要显示的任何文本)。实际需要时加载整个条目。

于 2012-07-07T22:03:01.653 回答