Вопрос по c# – Утилизирует ли Streamreader поток?

151

Я посылаю поток в методы для записи, и в этих методах я использую двоичное устройство чтения / записи. Когда читатель / писатель избавляется using или просто, когда на него нет ссылок, поток тоже закрыт ??

Я бы отправил BinaryReader / Writer, но я тоже использую StreamReader (возможно, мне следует обойти это. Я использую это только для GetLine и ReadLine). Это довольно хлопотно, если он закрывает поток каждый раз, когда закрывается писатель / читатель.

Ваш Ответ

7   ответов
184

StreamReader, StreamWriter, BinaryReader а такжеBinaryWriter все закрывают / удаляют свои базовые потоки при вызовеDispose на них. Oни Не утилизируйте поток, если читатель / писатель просто собирается мусором - вы всегда должны утилизировать читателя / писателя, желательно сusing заявление. (На самом деле ни у одного из этих классов нет финализаторов, и при этом они не должны быть.)

Лично я предпочитаю также использовать оператор для потока. Вы можете вложитьusing заявления без скобок довольно аккуратно:

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

Даже еслиusingператор @ для потока несколько избыточен (если только операторStreamReader конструктор выдает исключение) Я считаю, что это лучшая практика, как если бы вы избавились отStreamReader и просто используйте поток непосредственно позднее, у вас уже будет правильная семантика удаления.

@ Nefzen: Это потому, что нет никакой гарантии, в каком порядке будут завершены ваши объекты. Если как StreamReader, так и нижележащий Stream имеют право на завершение, GC может сначала завершить поток - тогда потоковый считыватель не будет иметь ссылку на поток. По этой причине вы можете высвобождать неуправляемые ресурсы только в рамках завершения (например, FileStream закрывает свой дескриптор файла Windows в своем завершении). О, и, конечно, если вы никогда не утилизируете, поток все равно будет в конечном итоге собран (и файл закрыт). Это просто очень плохая практика - не выбрасывать поток. JMarsch
Это вложение вызывает жалобу анализатора кода VS:CA2202 : Microsoft.Usage : Object 'stream' can be disposed more than once in method '...'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object. Должно ли это быть проигнорировано? До сих пор я не получил никаких исключений ... H.B.
О, хорошо, это происходит только при вызове Dispose, а не когда якобы завершается. Nefzen
@ H.B .: В этом случае это можно игнорировать. Или вы можете просто создать поток в вызове конструктораStreamReader. Предупреждение выглядит поддельным для меня, учитывая, что документы дляIDisposable.Dispose явно заявляет: «Если метод Dispose объекта вызывается более одного раза, объект должен игнорировать все вызовы после первого. Объект не должен вызывать исключение, если его метод Dispose вызывается несколько раз.» Jon Skeet
@ JonSkeet: На самом деле есть страница для этого, ты был прав, это фальшивка H.B.
36

но я хотел сделать что-то подобное сегодня и обнаружил, что все изменилось. Начиная с .net 4.5, естьleaveOpen аргумент:

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

Единственная проблема заключается в том, что не совсем очевидно, что нужно установить для других параметров. Вот некоторая помощь:

От страница MSDN для Конструктора StreamReader (Stream):

Этот конструктор инициализирует кодировку для UTF8Encoding, свойство BaseStream с использованием параметра stream и размер внутреннего буфера до 1024 байтов.

Это просто уходитdetectEncodingFromByteOrderMarks который судя по исходный код являетсяtrue

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

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

Было бы хорошо, если бы были выставлены некоторые из этих значений по умолчанию или если аргументы были необязательными, чтобы мы могли просто указать те, которые нам нужны.

Очень хорошая информация! Никогда не слышал об этом новом параметре, и он действительно имеет большой смысл. julealgon
Не заметил нового дополнения в 4.5, спасибо! TimothyP
Для ленивых людей, как я, короткий ответ, чтобы оставить поток открытым, будет выглядеть так:using (var streamReader = new StreamReader(myStream, Encoding.UTF8, true, 1024, true)) beawolf
27

это так. Вы можете убедиться в этом, посмотрев реализацию с помощью 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);
        }
    }
}
10

StreamReader закрывает соединение, когда оно удаляется. Однако "использование (Stream stream = ...) {...}" с StreamReader / StreamWriter может привести к тому, что поток будет удален дважды: (1) когда объект StreamReader удаляется (2) и когда блок Stream используя закрывается. Это приводит к предупреждению CA2202 при выполнении анализа кода VS.

Другое решение, взятое непосредственно из CA2202 page, это использовать блок try / finally. Настройте правильно, соединение будет закрыто только один раз.

Недалеко от CA2202, Microsoft рекомендует использовать следующее:

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

вместо того..

// Generates a CA2202 warning
using (Stream stream = new FileStream("file.txt", FileMode.Open))
using (XmlReader reader = new XmlReader (stream))
{
    // Use the reader object...
}
Да, это было очень полезно для меня, сейчас, 7 лет спустя Sebastian
Предупреждение также обсуждается в комментариях к принятому ответу. Джон Скит предлагает несколько советов там. Marcin
Также помните, что оператор using фактически преобразуется компилятором в блок try-finally. Loophole
2

авить объект очистить все свои ресурсы. Это включает в себя очистку потоков и закрытие их файловых дескрипторов.

Если в вашем случае вы хотите передать его другим методам, то вам нужно убедиться, что эти методы не выполняют чтение / запись в блоке using.

1

если вам нужно, это переопределить метод Dispose для класса StreamWriter. Смотрите мой пост здесь для кода о том, как это сделать:

Делает ли. StreamWriter закрыть основной поток?

-3

using", либо с помощью явного вызова dispose

Похожие вопросы