【问题标题】:Reading a null-terminated string读取以空字符结尾的字符串
【发布时间】:2018-10-24 01:44:49
【问题描述】:

我正在从二进制文件中读取字符串。每个字符串都以空值结尾。编码为 UTF-8。在 python 中,我只是读取一个字节,检查它是否为 0,将其附加到字节数组,然后继续读取字节,直到看到 0。然后我将字节数组转换为字符串并继续前进。所有字符串均已正确读取。

如何在 C# 中阅读此内容?由于数组是固定大小的,我不认为我可以简单地将字节附加到数组中。

【问题讨论】:

  • 为什么不将它们作为字符附加到字符串中?
  • 这可行,但会使用比您想象的更多的内存。 C# 字符串是不可变的,因此每次修改时都必须创建一个新字符串。在大多数情况下,额外内存的数量可能不是问题,但最好的方法可能是 Mike 的建议,具有合理的初始大小。 List 仍然只是一个数组的包装器,它在需要时创建更大的数组。
  • List 我猜似乎还不错。听起来和python的list一样。

标签: c#


【解决方案1】:

以下内容应该会为您提供所需的内容。所有文本都应该在 myText 列表中。

var data = File.ReadAllBytes("myfile.bin");
List<string> myText = new List<string>();
int lastOffset = 0;
for (int i = 0; i < data.Length; i++)
{
    if (data[i] == 0)
    {
        myText.Add(System.Text.Encoding.UTF8.GetString(data, lastOffset, i - lastOffset));
        lastOffset = i + 1;
    }
}

【讨论】:

  • 这应该是答案
【解决方案2】:

我假设您使用的是 StreamReader 实例:

StringBuilder sb = new StringBuilder();
using(StreamReader rdr = OpenReader(...)) {
    Int32 nc;
    while((nc = rdr.Read()) != -1) {
          Char c = (Char)nc;
          if( c != '\0' ) sb.Append( c );
    }
}

【讨论】:

  • 我喜欢我认为您(很久以前)的想法,但我认为您可能(明确)假设太多,所以请参阅我的扩展答案。
【解决方案3】:

您可以使用List&lt;byte&gt;:

List<byte> list = new List<byte>();
while(reading){ //or whatever your condition is
    list.add(readByte);
}

string output = Encoding.UTF8.GetString(list.ToArray());

或者你可以使用StringBuilder

StringBuilder builder = new StringBuilder();

while(reading){
    builder.Append(readByte);
}

string output = builder.ToString();

【讨论】:

  • -1:StringBuilder 不会append 字节的字符值,而是字节的整数值。
  • ReadChar() 可以解决这个问题: char c = reader.ReadChar(); builder.Append(c);
【解决方案4】:

如果您的“二进制文件”仅包含以空字符结尾的 UTF8 字符串,那么对于 .NET,它不是“二进制文件”,而只是一个文本文件,因为空字符也是字符。因此,您可以只使用 StreamReader 来读取文本并将其拆分为空字符。 (六年后,“你”可能会成为一些新读者,而不是 OP。)

单行(ish)解决方案是:

using (var rdr = new StreamReader(path))
    return rdr.ReadToEnd().split(new char[] { '\0' });

但是,如果文件中的最后一个字符串被“正确”终止,那将给你一个尾随的空字符串。

一个更详细的解决方案可能对非常大的文件执行不同的处理,表示为 StreamReader 上的扩展方法,将是:

List<string> ReadAllNullTerminated(this System.IO.StreamReader rdr)
{
    var stringsRead = new System.Collections.Generic.List<string>();
    var bldr = new System.Text.StringBuilder();
    int nc;
    while ((nc = rdr.Read()) != -1)
    {
        Char c = (Char)nc;
        if (c == '\0')
        {
            stringsRead.Add(bldr.ToString());
            bldr.Length = 0;
        }
        else
            bldr.Append(c);
    }

    // Optionally return any trailing unterminated string
    if (bldr.Length != 0)
        stringsRead.Add(bldr.ToString());

    return stringsRead;
}

或一次只阅读一个(如 ReadLine)

string ReadNullTerminated(this System.IO.StreamReader rdr)
{
    var bldr = new System.Text.StringBuilder();
    int nc;
    while ((nc = rdr.Read()) > 0)
        bldr.Append((char)nc);

    return bldr.ToString();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-07
    相关资源
    最近更新 更多