Есть ли способ закрыть StreamWriter, не закрывая его BaseStream? - PullRequest
103 голосов
/ 19 апреля 2010

Моя основная проблема заключается в том, что когда using вызывает Dispose на StreamWriter, он также удаляет BaseStream (та же проблема с Close).

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

Целью этого является получение содержимого строки (первоначально считанной из базы данных) в поток, чтобы поток мог быть прочитан сторонним компонентом.
NB : я не могу изменить сторонний компонент.

public System.IO.Stream CreateStream(string value)
{
    var baseStream = new System.IO.MemoryStream();
    var baseCopy = new System.IO.MemoryStream();
    using (var writer = new System.IO.StreamWriter(baseStream, System.Text.Encoding.UTF8))
    {
        writer.Write(value);
        writer.Flush();
        baseStream.WriteTo(baseCopy); 
    }
    baseCopy.Seek(0, System.IO.SeekOrigin.Begin);
    return baseCopy;
}

Используется как

public void Noddy()
{
    System.IO.Stream myStream = CreateStream("The contents of this string are unimportant");
    My3rdPartyComponent.ReadFromStream(myStream);
}

В идеале я ищу воображаемый метод, называемый BreakAssociationWithBaseStream, например,

public System.IO.Stream CreateStream_Alternate(string value)
{
    var baseStream = new System.IO.MemoryStream();
    using (var writer = new System.IO.StreamWriter(baseStream, System.Text.Encoding.UTF8))
    {
        writer.Write(value);
        writer.Flush();
        writer.BreakAssociationWithBaseStream();
    }
    return baseStream;
}

Ответы [ 5 ]

104 голосов
/ 19 апреля 2010

Если вы используете .NET Framework 4.5 или более позднюю версию, существует перегрузка StreamWriter, с помощью которой вы можете попросить оставить основной поток открытым при закрытии модуля записи .

В более ранних версиях .NET Framework до 4.5 StreamWriter предполагает, что владеет потоком. Опции:

  • Не выбрасывайте StreamWriter; просто промойте его.
  • Создайте потоковую оболочку, которая игнорирует вызовы Close / Dispose, но проксирует все остальное. У меня есть реализация этого в MiscUtil , если вы хотите взять его оттуда.
41 голосов
/ 19 февраля 2013

.NET 4.5 получил новый метод для этого!

http://msdn.microsoft.com/EN-US/library/gg712853(v=VS.110,d=hv.2).aspx

public StreamWriter(
    Stream stream,
    Encoding encoding,
    int bufferSize,
    bool leaveOpen
)
32 голосов
/ 19 апреля 2010

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

5 голосов
/ 30 марта 2012

Поток памяти имеет свойство ToArray, которое можно использовать, даже когда поток закрыт.To Array записывает содержимое потока в байтовый массив независимо от свойства Position.Вы можете создать новый поток на основе потока, в котором вы написали.

public System.IO.Stream CreateStream(string value)
{
    var baseStream = new System.IO.MemoryStream();
    var baseCopy = new System.IO.MemoryStream();
    using (var writer = new System.IO.StreamWriter(baseStream, System.Text.Encoding.UTF8))
    {
        writer.Write(value);
        writer.Flush();
        baseStream.WriteTo(baseCopy); 
    }
    var returnStream = new System.IO.MemoryStream( baseCopy.ToArray());
    return returnStream;
}
1 голос
/ 20 июля 2011

Вам нужно создать потомка StreamWriter и переопределить его метод dispose, всегда передавая false параметру распоряжения, это заставит потоковый писатель НЕ закрываться, StreamWriter просто вызывает dispose в методе close, поэтому нет необходимости переопределять его (конечно, вы можете добавить все конструкторы, если хотите, у меня есть только один):

public class NoCloseStreamWriter : StreamWriter
{
    public NoCloseStreamWriter(Stream stream, Encoding encoding)
        : base(stream, encoding)
    {
    }

    protected override void Dispose(bool disposing)
    {
        base.Dispose(false);
    }
}
...