Есть ли способ закрыть StreamWriter, не закрывая его BaseStream?

Моя коренная проблема в том, что когда 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 ответов

Решение

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

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

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

.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
)

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

Поток памяти имеет свойство 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;
}

Вам нужно создать потомка 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);
    }
}
Другие вопросы по тегам