0
votes

System.ArgumentOutOfRangeException: 'la capacité était inférieure à la taille actuelle. Nom du paramètre: requiredLength '

J'ai besoin de générer un alphanumérique aléatoire d'une longueur comprise entre 1k octets et 2K octets pour le stocker dans le csv

J'ai une erreur

System.ArgumentOutOfRangeException: 'la capacité était inférieure à la taille actuelle. Nom du paramètre: 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());
    }

Est-ce parce que la chaîne ne peut pas contenir autant de caractères? Y a-t-il un moyen de résoudre ce problème?


3 commentaires

À quelle ligne obtenez-vous cette erreur?


Sur la ligne 'csvcontent.AppendLine (ID + "," + stringContent);'


Vous essayez de créer un seul StringBuilder avec plus de 25 milliards de caractères, soit près de 50 Go. Vous devez plutôt écrire chaque ligne directement dans le fichier.


3 Réponses :


1
votes

Le StringBuilder dans .Net a des limites. Vérifiez la valeur de:

csvcontent.MaxCapacity;

Vous obtiendrez probablement 2,147,483,647 (qui est Int32.MaxValue). Je dis «probablement» parce que Microsoft dit que cela pourrait changer dans les futures implémentations.

Vous ne pouvez pas dépasser la taille renvoyée par cet appel (en fait, elle est légèrement plus petite en raison de la surcharge).

Vous devrez soit diviser votre chaîne en plusieurs StringBuilders ou, mieux encore, comprendre pourquoi vous créez une chaîne aussi grande et changer votre conception pour ne pas le faire, car il est inhabituel d'avoir besoin d'une chaîne aussi énorme, en pratique.

Pourquoi ne pas simplement ajouter les données au fichier directement dans la boucle au lieu d'utiliser le constructeur de chaînes intermédiaire?


0 commentaires

3
votes

Faisons le calcul ici.

Vous voulez écrire 100.000 lignes, avec ce format:

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}"));
}

Ignorons le (s) caractère (s) de saut de ligne à la fin pour simplifier. La ligne ci-dessus fait 36 + 1 + 256.000 caractères, 256.037 au total. Multipliez cela par 100 000 lignes et vous obtenez un nombre total de caractères de 25 603 700 000 caractères. Étant donné qu'un caractère en mémoire est stocké en tant que point de code Unicode 16 bits, cela signifie le double en termes d'octets, soit 51.207.400.000 octets, ce qui représente environ 47,7 Go de mémoire.

Dans un StringBuilder.

Ce n'est tout simplement pas possible. Un StringBuilder a une limite d'environ 2,1 millions de caractères et vous souhaitez y stocker 25 milliards de caractères.

Ce n'est tout simplement pas possible, et même si vous avez réussi à trouver un moyen de le contourner, ou si la limite d'un StringBuilder a été modifiée pour gérer cela, il n'est pas nécessaire de stocker cela en mémoire uniquement pour ensuite le vider dans un fichier. Au lieu de cela, écrivez-le directement dans votre fichier pour commencer. Voici une traduction littérale de votre code, qui peut encore être simplifiée un peu.

<guid>,<256.000 characters>

Notez que cela ajoutera environ 27-28 Go au fichier. Je remets en question l'utilisation que vous pourriez avoir pour un fichier texte de cette taille, à ce stade, je commencerais probablement à penser à une base de données, car la recherche d'un Guid dans ce gros fichier aura des performances très faibles.


0 commentaires

0
votes

Comme @JesseChunn l'a déjà mentionné, je pense que vous devriez vérifier pourquoi vous générez des chaînes aussi énormes. Si je ne me trompe pas, vous essayez de générer près de 24 Go de données de chaîne aléatoire, n'est-ce pas?

Mais si vous avez toujours besoin de créer une grande quantité de données de chaîne, vous pouvez écrire les chaînes aléatoires directement dans le fichier.

par exemple

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());
}


0 commentaires