streamWriterBufferedDataLost (MDA)

L’Assistant Débogage managé streamWriterBufferedDataLost est activé lors d’une écriture dans StreamWriter, mais la méthode Flush ou Close n’est pas appelée par la suite avant la destruction de l’instance du StreamWriter. Quand cet Assistant Débogage managé est activé, le runtime détermine s’il existe encore des données mises en mémoire tampon dans StreamWriter. Si c’est le cas, l’Assistant Débogage managé est activé. L’appel aux méthodes Collect et WaitForPendingFinalizers peut forcer des finaliseurs à s’exécuter. Sinon, les finaliseurs s’exécuteront à des moments apparemment arbitraires, voire pas du tout lors de la sortie du processus. L’exécution explicite des finaliseurs avec cet Assistant Débogage managé activé aide à reproduire ce type de problème de façon plus fiable.

Symptômes

Un StreamWriter n’écrit pas les 1 à 4 derniers kilo-octets de données dans un fichier.

Cause

Le StreamWriter met les données en mémoire tampon en interne, ce qui exige un appel à la méthode Close ou Flush pour écrire les données mises en mémoire tampon dans le magasin de données sous-jacent. Si Close ou Flush n’est pas appelée au moment opportun, les données mises en mémoire tampon dans l’instance de StreamWriter peuvent ne pas être écrites comme prévu.

L’exemple suivant illustre un code mal écrit que cet Assistant Débogage managé doit intercepter.

// Poorly written code.  
void Write()
{  
    StreamWriter sw = new StreamWriter("file.txt");  
    sw.WriteLine("Data");  
    // Problem: forgot to close the StreamWriter.  
}  

Le code précédent activera cet Assistant Débogage managé de façon plus fiable si un garbage collection est déclenché avant d’être suspendu jusqu’au terme de l’exécution des finaliseurs. Pour repérer ce type de problème, vous pouvez ajouter le code suivant à la fin de la méthode précédente dans une version Debug. Cela permet d’activer systématiquement l’Assistant Débogage managé même si cela ne résout évidemment pas la cause du problème.

GC.Collect();  
GC.WaitForPendingFinalizers();  

Résolution

Veillez à appeler Close ou Flush sur le StreamWriter avant de fermer une application ou tout bloc de code possédant une instance de StreamWriter. Pour ce faire, une des solutions les plus efficaces consiste à créer l’instance avec un bloc using C# (Using en Visual Basic) qui garantit l’appel à la méthode Dispose pour le writer, ce qui permet de fermer correctement l’instance.

using(StreamWriter sw = new StreamWriter("file.txt"))
{  
    sw.WriteLine("Data");  
}  

Le code suivant illustre la même solution, à l’aide de try/finally au lieu d’using.

StreamWriter sw;  
try
{  
    sw = new StreamWriter("file.txt"));  
    sw.WriteLine("Data");  
}  
finally
{  
    if (sw != null)  
        sw.Close();  
}  

Si aucune de ces solutions ne peut être utilisée (par exemple, si un StreamWriter est stocké dans une variable statique et que vous ne pouvez pas exécuter facilement du code à la fin de sa durée de vie), l’appel à Flush sur le StreamWriter après sa dernière utilisation ou l’affectation de la valeur true à la propriété AutoFlush avant sa première utilisation doit éviter ce problème.

private static StreamWriter log;  
// static class constructor.  
static WriteToFile()
{  
    StreamWriter sw = new StreamWriter("log.txt");  
    sw.AutoFlush = true;  
  
    // Publish the StreamWriter for other threads.  
    log = sw;  
}  

Effet sur le runtime

Cet Assistant Débogage managé n'a aucun effet sur le runtime.

Sortie

Un message signale cette violation.

Configuration

<mdaConfig>  
  <assistants>  
    <streamWriterBufferedDataLost />  
  </assistants>  
</mdaConfig>  

Voir aussi