web-dev-qa-db-fra.com

L'élimination de streamreader ferme-t-elle le flux?

J'envoie un flux aux méthodes sur lesquelles écrire, et j'utilise un lecteur/enregistreur binaire. Lorsque le lecteur/rédacteur est éliminé, soit par using, soit juste au moment où il n'est pas référencé, le flux est-il également fermé?

J'enverrais un BinaryReader/Writer, mais j'utilise aussi un StreamReader (peut-être que je devrais contourner cela. Je ne l'utilise que pour GetLine et ReadLine). C'est assez gênant si le flux est fermé chaque fois qu'un écrivain/lecteur est fermé.

155
Nefzen

Oui, StreamReader, StreamWriter, BinaryReader et BinaryWriter ferment/suppriment leurs flux sous-jacents lorsque vous appelez Dispose. Ils ne le font pas suppriment le flux si le lecteur/écrivain est juste un ramasse-miettes, vous devriez toujours disposer du lecteur/écrivain, de préférence avec une instruction using. (En fait, aucune de ces classes n'a de finaliseur, et ne devrait pas en avoir.)

Personnellement, je préfère également avoir une instruction using pour le flux. Vous pouvez imbriquer parfaitement les instructions using sans accolades:

using (Stream stream = ...)
using (StreamReader reader = new StreamReader(stream, Encoding.Whatever))
{
}

Même si l'instruction using du flux est quelque peu redondante (à moins que le constructeur StreamReader ne lève une exception), je considère qu'il est préférable de le faire si vous vous débarrassiez de StreamReader et utilisez le flux directement à une date ultérieure, vous aurez déjà la bonne sémantique de destruction.

192
Jon Skeet

C'est un vieux, mais je voulais faire quelque chose de similaire aujourd'hui et j'ai constaté que les choses avaient changé. Depuis .net 4.5, il existe un argument leaveOpen:

public StreamReader( Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize, bool leaveOpen )

Le seul problème est qu'il n'est pas tout à fait évident de définir ce qu'il faut définir pour les autres paramètres. Voici de l'aide:

De la page msdn pour le constructeur StreamReader (Stream):

Ce constructeur initialise le codage sur UTF8Encoding, la propriété BaseStream à l'aide du paramètre stream et la taille de la mémoire tampon interne sur 1024 octets.

Cela laisse juste detectEncodingFromByteOrderMarks qui juge de le code source est true

public StreamReader(Stream stream)
        : this(stream, true) {
}

public StreamReader(Stream stream, bool detectEncodingFromByteOrderMarks)
        : this(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks, DefaultBufferSize) {
}

Ce serait bien si certaines de ces valeurs par défaut étaient exposées ou si les arguments étaient facultatifs afin que nous puissions spécifier ceux que nous souhaitons.

41
acarlon

Oui. Vous pouvez le vérifier en regardant l’implémentation avec Reflector.

protected override void Dispose(bool disposing)
{
    try
    {
        if ((this.Closable && disposing) && (this.stream != null))
        {
            this.stream.Close();
        }
    }
    finally
    {
        if (this.Closable && (this.stream != null))
        {    
            this.stream = null;    
            this.encoding = null;
            this.decoder = null;
            this.byteBuffer = null;
            this.charBuffer = null;
            this.charPos = 0;
            this.charLen = 0;
            base.Dispose(disposing);
        }
    }
}
29
Brian Rasmussen

Six ans de retard, mais peut-être que cela pourrait aider quelqu'un.

StreamReader ferme la connexion lorsqu'elle est supprimée. Cependant, "using (Stream stream = ...) {...}" avec StreamReader/StreamWriter peut entraîner la suppression du flux à deux reprises: (1) lorsque l'objet StreamReader est supprimé (2) et lorsque le flux à l'aide du bloc se ferme. Cela entraîne un avertissement CA2202 lors de l'exécution de l'analyse de code de VS.

Une autre solution, directement à partir de la page CA2202 , consiste à utiliser un bloc try/finally. Si vous l’installez correctement, la connexion ne sera fermée qu’une fois.

Au bas de CA2202 , Microsoft vous recommande d'utiliser les éléments suivants:

Stream stream = null;
try
{
    stream = new FileStream("file.txt", FileMode.OpenOrCreate);
    using (StreamWriter writer = new StreamWriter(stream))
    {
        stream = null;
        // Use the writer object...
    }
}
finally
{
    if(stream != null)
        stream.Dispose();
}

au lieu de...

// Generates a CA2202 warning
using (Stream stream = new FileStream("file.txt", FileMode.Open))
using (XmlReader reader = new XmlReader (stream))
{
    // Use the reader object...
}
13
Sunsetquest

Oui. L'appel de Dispose () sur et IDisposable (que "using" fait) devrait obliger un objet à nettoyer toutes ses ressources. Cela inclut le vidage des flux et la fermeture de leurs descripteurs de fichiers.

Si, dans votre cas, vous souhaitez le transférer à d'autres méthodes, vous devez vous assurer que ces méthodes ne font pas leur lecture/écriture dans un bloc using.

2
Joe M

Un moyen simple de résoudre ce problème est de remplacer la méthode Dispose des classes StreamWriter. Voir mon post ici pour le code sur la façon de le faire:

Est-ce que .Disposing un StreamWriter ferme le flux sous-jacent?

1
Aaron Murgatroyd