J'ai besoin de lire un flux deux fois, du début à la fin.
Mais le code suivant jette un ObjectDisposeception: impossible d'accéder à un fichier fermé code> Exception. P>
string fileToReadPath = @"<path here>";
using (FileStream fs = new FileStream(fileToReadPath, FileMode.Open))
{
using (StreamReader reader = new StreamReader(fs))
{
string text = reader.ReadToEnd();
Console.WriteLine(text);
}
fs.Seek(0, SeekOrigin.Begin); // ObjectDisposedException thrown.
using (StreamReader reader = new StreamReader(fs))
{
string text = reader.ReadToEnd();
Console.WriteLine(text);
}
}
6 Réponses :
Le but de Pour corriger votre code, utilisez simplement un lecteur tout le temps: p> modifié pour traiter les commentaires ci-dessous strong>: < / p> Dans la plupart des situations, vous n'avez pas besoin d'accéder au flux sous-jacent que vous le faites dans votre code ( Dispose () code> est de nettoyer les ressources lorsque vous avez terminé avec le flux. La raison pour laquelle le lecteur em> impacte le le flux em> est dû au fait que le lecteur ne fait que filtrer le flux, et donc disposer que le lecteur n'a pas de sens, sauf dans le contexte de celui-ci en chaisant l'appel à la Source Stream aussi.
fs.seek code>). Dans ces cas, le fait que
streamdreader code> chaîne son appel dans le flux sous-jacent vous permet d'économiser sur le code en n'utilisant pas de déclaration code> code> pour le flux. Par exemple, le code ressemblerait à: p>
En fait, je demande pourquoi disposer () sur le lecteur i> affecte le flux i>. Je ne comprends pas votre réponse. Cela signifie-t-il que les lecteurs disposent uniquement d'un objectif de nettoyer les données de flux? Alors pourquoi même streamreader code> implémente
Idisposable code>, s'il ne fait rien utile i> (puisque dispose le flux lui-même fera dans tous les cas. )?
@Mainma, le but de Dispose () est toujours i> pour vous assurer que toutes les ressources associées au code> indiquées code> sont nettoyées. Étant donné que le lecteur et le flux représentent la même entité éliminant l'un a le même effet que l'élimination de l'autre.
en utilisant code> définit une portée, en dehors de laquelle un objet sera disposé, donc la
objetdisposeception code>. Vous ne pouvez pas accéder au contenu de StreamReader en dehors de ce bloc. p>
Cela se produit parce que le Il y a un constructeur pour Dans ce cas particulier, vous résoudriez le problème en n'utilisant pas le code> à l'aide de code> -Statement du StreamReader code> reprend "propriété" du flux. En d'autres termes, il se rend responsable de la fermeture du flux source. Dès que votre programme appelle
Dispose code> ou
Fermer code> (laissant le
à l'aide de code> de la portée de l'instruction dans votre cas), il dispose également du flux source également. Appeler
fs.dispose () code> dans votre cas. Donc, le flux de fichiers est mort après avoir quitté le premier
en utilisant le bloc code>. C'est un comportement cohérent, toutes les classes de flux dans .net qui enveloppent un autre flux se comportent de cette façon. P>
streamreader code> qui permet de dire qu'il ne possède pas em> posséder le flux source. Il n'est cependant pas accessible à partir d'un programme .NET, le constructeur est interne. P>
streamreader code>. C'est cependant un détail de mise en œuvre assez velu. Il y a sûrement une meilleure solution à votre disposition mais le code est trop synthétique pour proposer un vrai. P>
Dispose () code> sur le parent
disposera () code> Tous les flux appartenant. Malheureusement, les flux n'ont pas
détach () code> méthode, vous devez donc créer une solution de contournement ici. P>
Je ne sais pas pourquoi, mais vous pouvez laisser votre streamrired non déconposé. De cette façon, votre flux sous-jacent ne sera pas disposé, même lorsque celui-ci a été collecté. P>
Bien sûr. Mais il n'est pas trop intuitif de ne pas mettre à l'aide d'un StreamReader code> pour moi, et cela violera probablement les règles FXCOP. Au fait, la question à l'origine de cette question est apparue lorsque j'ai refoulé et un code ancien où nous manquions complètement.
Je suis d'accord avec votre question. Le plus gros problème avec cet effet secondaire intentionnel est lorsque les développeurs ne le savent pas et sont aveuglément à la suite de la "meilleure pratique" de l'entourage d'un streamerrieur avec un Le développeur n'avait aucune idée L'intrustream est désormais hosté pour tout lieu futur qui s'attend à ce qu'il soit là. P> Évidemment, une fois que vous connaissez les internes, vous savez éviter le Ce que je fais et dit à nos développeurs de faire sur les instances de flux que le code de lecture ne crée pas explicitement est ... P> en utilisant code>. Mais cela peut causer des bugs très difficiles à suivre les bugs lorsqu'il est sur la propriété d'un objet de longue durée, le meilleur (pire?) Que j'ai vu est
en utilisant code> et simplement lire et réinitialiser la position. . Mais je pensais qu'un principe fondamental de la conception de l'API était d'éviter les effets secondaires, en particulier de ne pas détruire les données que vous agissez. Rien non inhérent à une classe qui est supposée être un "lecteur" devrait effacer les données qu'il se lit lorsqu'il est fait "en utilisant". L'élimination du lecteur doit libérer les références au flux, non pas effacer le flux lui-même. La seule chose à laquelle je puisse penser, c'est que le choix devait être fait car le lecteur modifie un autre état interne du flux, comme la position du pointeur de recherche, qu'elles supposaient que si vous envisagez de l'utiliser autour de cela, vous allez intentionnellement être fait avec tout. D'autre part, comme dans votre exemple, si vous créez un flux, le flux lui-même sera dans un
en utilisant code>, mais si vous lisez un flux créé en dehors de votre méthode immédiate, Il est présomptueux du code pour effacer les données. P>
// save position before reading
long position = theStream.Position;
theStream.Seek(0, SeekOrigin.Begin);
// DO NOT put this StreamReader in a using, StreamReader.Dispose() clears the stream
StreamReader sr = new StreamReader(theStream);
string content = sr.ReadToEnd();
theStream.Seek(position, SeekOrigin.Begin);
Un meilleur design pour un rationniste aurait été d'avoir un argument de constructeur préciser si cela devrait s'approprier le flux. Il existe de nombreuses situations dans lesquelles le code peut ouvrir un flux, créer un lecteur pour cela, remettre le lecteur à quelque chose qui lira les données à un moment futur, puis n'a plus d'utilisation pour le flux. Dans cette situation, le flux devrait être disposé lorsque le lecteur est effectué avec elle, mais le créateur du flux n'a peut-être aucune idée de ce qui sera.
Envisagez également d'utiliser System.IO.FILE.ReadallText () dans des situations comme celles-ci. C'est plus simple.
@Dave Markle: Tu as raison. Je l'ai dit comme un court exemple. En fait, dans le code réel, les flux que je traite peuvent être très gros, le premier lecteur leur lit la ligne par ligne, puis le flux est copié par octet vers un autre flux.