web-dev-qa-db-fra.com

Lecture du flux de mémoire en chaîne

J'essaie d'écrire un objet dans une chaîne XML et de prendre cette chaîne et de l'enregistrer dans une base de données. Mais je dois d'abord avoir la ficelle ...

    private static readonly Encoding LocalEncoding = Encoding.UTF8;

    public static string SaveToString<T> (T settings)
    {
        Stream stream = null;
        TextWriter writer = null;
        string settingsString = null;

        try
        {
            stream = new MemoryStream();

            var serializer = new XmlSerializer(typeof(T));

            writer = new StreamWriter(stream, LocalEncoding);

            serializer.Serialize(writer, settings);

            var buffer = new byte[stream.Length];

            stream.Read(buffer, 0, (int)stream.Length);

            settingsString = LocalEncoding.GetString(buffer);
        }
        catch(Exception ex)
        {
            // If the action cancels we don't want to throw, just return null.
        }
        finally
        {
            if (stream != null)
                stream.Close();

            if(writer != null)
                writer.Close();
        }

        return settingsString;
    }

Cela semble fonctionner, le flux est rempli d'octets. Mais quand je viens de le relire dans le tampon puis dans la chaîne ... le tampon est rempli de '0'! Je ne sais pas ce que je fais mal, les gars.

37

Si vous aviez vérifié les résultats de stream.Read, vous auriez vu qu'il n'avait rien lu - parce que vous n'avez pas rembobiné le flux. (Vous pouvez le faire avec stream.Position = 0;.) Cependant, il est plus facile d'appeler simplement ToArray:

settingsString = LocalEncoding.GetString(stream.ToArray());

(Vous devrez changer le type de stream de Stream à MemoryStream, mais c'est correct car c'est dans la même méthode que celle que vous avez créée.)

Sinon, et plus simplement encore, utilisez simplement StringWriter au lieu de StreamWriter. Vous aurez besoin de créer une sous-classe si vous voulez utiliser UTF-8 au lieu de UTF-16, mais c'est assez facile. Voir cette réponse pour un exemple.

Je suis préoccupé par la façon dont vous attrapez simplement Exception et en supposant que cela signifie en fait quelque chose d'inoffensif - sans même enregistrer n'importe quoi. Notez que les instructions using sont généralement plus propres que l'écriture de blocs explicites finally.

75
Jon Skeet
string result = System.Text.Encoding.UTF8.GetString(fs.ToArray());
19
Farzad J
string result = Encoding.UTF8.GetString((stream as MemoryStream).ToArray());
6
evorios

En cas de très grande longueur de flux, il existe un risque de fuite de mémoire dû à Large Object Heap . c'est-à-dire que le tampon d'octets créé par stream.ToArray crée une copie du flux de mémoire dans la mémoire de segment de mémoire, ce qui entraîne la duplication de la mémoire réservée. Je suggérerais d'utiliser un StreamReader, un TextWriter et de lire le flux en morceaux de tampons char.

Dans netstandard2.0 System.IO.StreamReader a une méthode ReadBlock

vous pouvez utiliser cette méthode pour lire l'instance d'un Stream (une instance de MemoryStream également puisque Stream est le super de MemoryStream):

private static string ReadStreamInChunks(Stream stream, int chunkLength)
{
    stream.Seek(0, SeekOrigin.Begin);
    string result;
    using(var textWriter = new StringWriter())
    using (var reader = new StreamReader(stream))
    {
        var readChunk = new char[chunkLength];
        int readChunkLength;
        //do while: is useful for the last iteration in case readChunkLength < chunkLength
        do
        {
            readChunkLength = reader.ReadBlock(readChunk, 0, chunkLength);
            textWriter.Write(readChunk,0,readChunkLength);
        } while (readChunkLength > 0);

        result = textWriter.ToString();
    }

    return result;
}

NB Le risque de fuite de mémoire n'est pas totalement éliminé, en raison de l'utilisation de MemoryStream, ce qui peut entraîner une fuite de mémoire pour une instance de flux de mémoire volumineuse (memoryStreamInstance.Size> 85 000 octets). Vous pouvez utiliser flux de mémoire recyclable , afin d'éviter LOH. C'est le pertinent bibliothèque

2
George Kargakis