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

Edw*_*vey 21 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);
}
Run Code Online (Sandbox Code Playgroud)

Eri*_*ert 14

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


Sco*_*ain 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();
}
Run Code Online (Sandbox Code Playgroud)

  • 对于那个给我一个-1的人来说,你的答案是什么,你认为"无用"来保证-1?如果我的帖子中有不正确的信息,请通知我,以便我可以更正或删除它.我猜想代码编写内部`try-finally`的方式是不必要的.我会删除它.我能想到的另一件事就是`aes`和`scratch`在`myCryptoStream`之前被处理掉了.我也会纠正. (2认同)

The*_*tor 9

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

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

MSDN
CryptoStream.Dispose(bool disposing)

  • +1出于某种奇怪的原因,我无法调用构造函数的这个重载,但是,我能够设置`_leaveOpen`标志[通过反射](/sf/answers/909581921/)一样的效果 (3认同)
  • @StuartLC您是否在编写.NET Standard 2.0库?附加的构造函数不是.NET Standard 2.0的一部分,因为它将破坏与不存在该构造函数的.NET Framework 4.6.1的向后兼容性。 (2认同)

Edw*_*vey 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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • `scrach.Flush()`确实是unnessasary,[来自msdn](http://msdn.microsoft.com/en-us/library/system.io.memorystream.flush.aspx)"*覆盖Stream.Flush方法,以便不执行任何操作.*" (2认同)

小智 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 );
    }
}
Run Code Online (Sandbox Code Playgroud)