【问题标题】:System.ArgumentOutOfRangeException: 'capacity was less than the current size. Parameter name: requiredLength'System.ArgumentOutOfRangeException: '容量小于当前大小。参数名称:requiredLength'
【发布时间】:2020-11-16 14:26:35
【问题描述】:

我需要生成一个长度在 1k 字节到 2K 字节之间的随机字母数字,以将其存储到 csv

我遇到了一个错误

System.ArgumentOutOfRangeException: '容量小于 目前的规模。参数名称:requiredLength'

    private const String chars = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    protected void Button1_Click(object sender, EventArgs e)
    {
        String ID;
        String stringContent;
        int records = 100000;
        StringBuilder csvcontent = new StringBuilder();

        for (int r = 0; r < records; r++)
        {
            Guid guid = Guid.NewGuid();
            ID = guid.ToString();
            stringContent = GenerateRandomString(256000);
            csvcontent.AppendLine(ID + "," + stringContent);
        }

        File.AppendAllText(csvPath, csvcontent.ToString());
    }

    File.AppendAllText(csvPath, csvcontent.ToString());

    private string GenerateRandomString(int strLength)
    {
        return new string(Enumerable.Repeat(chars, strLength)
          .Select(s => s[random.Next(s.Length)]).ToArray());
    }

是不是因为字符串不能容纳那么多字符?有什么办法可以解决吗?

【问题讨论】:

  • 您在哪一行收到此错误?
  • 上线'csvcontent.AppendLine(ID + "," + stringContent);'
  • 您正在尝试创建一个长度超过 250 亿个字符的 StringBuilder,即接近 50GB。您应该改为将每一行直接写入文件。

标签: c# asp.net visual-studio csv


【解决方案1】:

让我们在这里算一下。

您想使用以下格式写入 100.000 行:

<guid>,<256.000 characters>

为了简单起见,让我们忽略末尾的换行符。上述行长 36+1+256.000 个字符,共 256.037 个。将其乘以 100.000 行,得到的字符总数为 25.603.700.000 个字符。由于内存中的字符存储为 16 位 unicode 代码点,这意味着字节数的两倍,即 51.207.400.000 字节,大约是 47.7GB 内存。

在一个 StringBuilder 中。

这根本不可能。 StringBuilder 有大约 2.1 百万 个字符的限制,而您想在其中存储 250 亿 个字符。

这根本不可能,即使您设法找到解决方法,或者 StringBuilder 的限制已更改为处理此问题,也无需将其存储在内存中,然后再将其转储到文件中。相反,只需将其直接写入您的文件即可。这是您的代码的字面翻译,可以进一步简化。

protected void Button1_Click(object sender, EventArgs e)
{
    int records = 100000;

    File.AppendAllLines(csvPath,
        (from r in Enumerable.Range(0, records)
         let guid = Guid.NewGuid()
         let stringContent = GenerateRandomString(256000)
         select $"{guid},{stringContent}"));
}

请注意,这将为文件增加大约 27-28GB。我质疑您对这种大小的 text 文件的使用情况,此时我可能会开始考虑数据库,因为在这个大文件中搜索 Guid 会非常低性能。

【讨论】:

    【解决方案2】:

    .Net 中的 StringBuilder 有限制。检查值:

    csvcontent.MaxCapacity;
    

    您可能会得到 2,147,483,647(即 Int32.MaxValue)。我说“可能”是因为微软表示这可能会在未来的实施中发生变化。

    您不能超过从该调用返回的大小(实际上它由于开销而略小)。

    您将需要将您的字符串分成多个 StringBuilders,或者更好的是,弄清楚您为什么要创建如此大的字符串并更改您的设计以不这样做,因为需要如此大的字符串是不寻常的,实际上。

    为什么不直接在循环内将数据附加到文件中,而不是使用中间字符串构建器?

    【讨论】:

      【解决方案3】:

      正如@JesseChunn 已经提到的,我认为您应该检查为什么会生成如此大的字符串。 如果我没记错的话,您正在尝试生成近 24 GB 的随机字符串数据,对吗?

      但如果您仍然需要创建大量字符串数据,您可以将随机字符串直接写入文件。

      例如

      private const String chars = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
      protected void Button1_Click(object sender, EventArgs e)
      {
          String ID;
          byte[] stringContent;
          int records = 100000;
      
          using(var textWriter = File.AppendText(csvPath))
          {
              for (int r = 0; r < records; r++)
              {
                  Guid guid = Guid.NewGuid();
                  ID = guid.ToString();
                  stringContent = GenerateRandomString(256000);
                  textWriter.WriteLine($"{ID}, {stringContent}");
               }
          }      
      }
      
      private string GenerateRandomString(int strLength)
      {
          return new string(Enumerable.Repeat(chars, strLength)
            .Select(s => s[random.Next(s.Length)]).ToArray());
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-22
        • 2022-10-23
        • 2017-05-24
        • 2012-04-25
        • 2011-11-26
        • 2019-10-24
        相关资源
        最近更新 更多