将虚幻引擎 4 二进制保存文件中的字符串添加到列表/数组

问题描述

我正在尝试读取以二进制形式保存的游戏保存文件。具体来说,我想将所有完整的字符串分别添加到数组中。我目前有这个代码

using (FileStream stream = new FileStream(path,FileMode.Open,FileAccess.Read,FileShare.ReadWrite))
{
    using (BinaryReader reader = new BinaryReader(stream))
    {
        while (reader.BaseStream.Position != reader.BaseStream.Length)
        {
            Console.WriteLine(reader.ReadString() + "\n");
        }
    }
}

但是,可以理解的是,这是胡言乱语,因为我相信我的 while 循环一次前进 1 个字节。如何可靠地找到保存文件中的每个“实际”单词?作为参考,以下是我想提取的在十六进制编辑器中查看的信息:image

一个出现的解决方案是遍历文件中的所有字节并以这种方式读取字符:

StringBuilder sBuilder = new StringBuilder();
bool inBuildState = false;
foreach (byte currByte in File.ReadAllBytes(path)) {
    bool isChar = currByte >= 0x20 && currByte <= 0x7F;

    if (inBuildState && !isChar) {
        Console.WriteLine(sBuilder.ToString() + "\n");
        sBuilder.Clear();
    }

    inBuildState = isChar;
    if (inBuildState) sBuilder.Append((char)currByte);
}

这个解决方效果很好,实际上并返回了我需要的字符串。非常感谢@Flydog57。

解决方法

你不能。

BinaryReader API 的工作方式是它可以读取您编写的文件,或者您知道符合特定格式的文件。在 ReadString() 的情况下,它读取第一个字节以获得后续字符串的长度,如果最高有效位为 1,则该长度在下一个字节中继续,依此类推。之后,它根据当前编码读取一定数量的字节,然后将这些字节解码为字符串。

但是您拥有的文件不是由 BinaryWriter 写入的,因此 BinaryReader 无法读取它。您的文件以 00 开头,因此表示字符串长度为 0。

您需要自定义代码来从此文件中读取字节并将字节解码为字符串。如果忽略 00 序列,出现所有字符串都以 00 00 0x 00 开头。

,

这可能是我的用例独有的,但这是我最终解决问题的方法;由于虚幻引擎 4 生成的二进制文件在很多地方都是乱码,因此无法解释为纯文本。所以我必须先把它变成这样。
我为此使用了正则表达式模式,用空格替换了不属于它的任何字符,从而导致一行有很多空格。然后我将字符串完全拆分为这些空格,并使用 LINQ 忽略所有空结果(空格)。这给我留下了所有真实字符串/单词的 IEnumerable<string>,我将其转换为 List<string>(因为这是我需要的)。

这是我的代码:

// Regular expression containing a-z,A-Z,0-9,-,_,and space.
Regex regex = new Regex("[^a-zA-Z0-9 -_]");

// Reading the file and immediately replacing all characters not part of the regex with spaces.
string fileToPlainText = regex.Replace(File.ReadAllText(filePath)," ");

// Creating a list of all items that aren't empty strings after splitting the string on spaces.
List<string> plainTextToList = fileToPlainText.Split(' ').Where(x => !String.IsNullOrEmpty(x)).ToList();

所需的 using 指令如下:

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