24

我创建一个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);
}
4

5 回答 5

17

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

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

MSDN
CryptoStream.Dispose(bool disposing)

于 2018-06-15T15:41:50.490 回答
15

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

于 2013-11-02T15:39:41.483 回答
10

您可以但不能使用 using 语句。您将需要手动管理对象的处置,您还需要调用FlushFinialBlock()以确保在处理之前将所有数据写入底层流。

一旦您完成了对流的所有处理,您就可以在最后的 finally 块中处理您等待的所有资源。

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();
}
于 2013-11-01T22:54:07.383 回答
7

我的简单解决方案:

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 );
    }
}
于 2015-01-21T01:12:23.917 回答
5

事实证明,没有任何必要将 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);
        }
    }
}
于 2013-11-02T14:14:51.940 回答