CryptoStream可以让基本流保持打开状态吗?

时间:2013-11-01 22:47:32

标签: c# stream objectdisposedexception

我创建了一个MemoryStream,将其传递给CryptoStream进行写作。我希望CryptoStream加密,然后让MemoryStream对我开放,然后阅读其他内容。但是,只要处置CryptoStream,它就会处置MemoryStream

可以CryptoStream以某种方式打开基地MemoryStream吗?

using (MemoryStream scratch = new MemoryStream())
{
    using (AesManaged aes = new AesManaged())
    {
        // <snip>
        // Set some aes parameters, including Key, IV, etc.
        // </snip>
        ICryptoTransform encryptor = aes.CreateEncryptor();
        using (CryptoStream myCryptoStream = new CryptoStream(scratch, encryptor, CryptoStreamMode.Write))
        {
            myCryptoStream.Write(someByteArray, 0, someByteArray.Length);
        }
    }
    // Here, I'm still within the MemoryStream block, so I expect
    // MemoryStream to still be usable.
    scratch.Position = 0;    // Throws ObjectDisposedException
    byte[] scratchBytes = new byte[scratch.Length];
    scratch.Read(scratchBytes,0,scratchBytes.Length);
    return Convert.ToBase64String(scratchBytes);
}

5 个答案:

答案 0 :(得分:13)

作为第二种解决方案,您可以创建一个WrapperStream对象,该对象只传递除Dispose / Close之外的每个调用。围绕内存流创建一个包装器,将包装器交给加密流,现在关闭加密流不会触及内存流。

答案 1 :(得分:10)

您可以,但您将无法使用using语句。您需要手动管理对象的处理,并且还需要调用FlushFinialBlock()以确保在处理之前将所有数据写入基础流。

完成所有流程后,您可以在最后一个块中处理等待的所有资源。

MemoryStream scratch = null;
AesManaged aes = null;
CryptoStream myCryptoStream = null;
try
{
    scratch = new MemoryStream();
    aes = new AesManaged();

    // <snip>
    // Set some aes parameters, including Key, IV, etc.
    // </snip>
    ICryptoTransform encryptor = aes.CreateEncryptor();
    myCryptoStream = new CryptoStream(scratch, encryptor, CryptoStreamMode.Write);
    myCryptoStream.Write(someByteArray, 0, someByteArray.Length);

    //Flush the data out so it is fully written to the underlying stream.
    myCryptoStream.FlushFinalBlock();

    scratch.Position = 0; 
    byte[] scratchBytes = new byte[scratch.Length];
    scratch.Read(scratchBytes,0,scratchBytes.Length);
    return Convert.ToBase64String(scratchBytes);
}
finally
{
    //Dispose all of the disposeable objects we created in reverse order.

    if(myCryptoStream != null)
        myCryptoStream.Dispose();

    if(aes != null)
        aes.Dispose();

    if(scratch != null)
        scratch.Dispose();
}

答案 2 :(得分:7)

从.NET 4.7.2开始,第二个构造函数添加了一个名为leaveOpen的bool参数。如果将其设置为true,那么CryptoStream的dispose方法将不会在基础流上调用dispose。

Additionally,没有leaveOpen参数的其他构造函数只是将参数转发给leaveOpen设置为false的新构造函数。

MSDN
CryptoStream.Dispose(bool disposing)

答案 3 :(得分:6)

事实证明,没有必要将using {}块分解为try {} finally {} ......最终,你只需要在using语句中使用FlushFinalBlock(),并嵌套其他东西必要时在里面。

using (MemoryStream scratch = new MemoryStream())
{
    using (AesManaged aes = new AesManaged())
    {
        // <snip>
        // Set some aes parameters, including Key, IV, etc.
        // </snip>
        ICryptoTransform encryptor = aes.CreateEncryptor();
        using (CryptoStream myCryptoStream = new CryptoStream(scratch, encryptor, CryptoStreamMode.Write))
        {
            myCryptoStream.Write(someByteArray, 0, someByteArray.Length);
            myCryptoStream.FlushFinalBlock();
            scratch.Flush();   // not sure if this is necessary
            byte[] scratchBytes = scratch.ToArray();
            return Convert.ToBase64String(scratchBytes);
        }
    }
}

答案 4 :(得分:5)

我的简单解决方案:

class NotClosingCryptoStream : CryptoStream
{
    public NotClosingCryptoStream( Stream stream, ICryptoTransform transform, CryptoStreamMode mode )
        : base( stream, transform, mode )
    {
    }

    protected override void Dispose( bool disposing )
    {
        if( !HasFlushedFinalBlock )
            FlushFinalBlock();

        base.Dispose( false );
    }
}