C# 加密流是否可以使基流保持打开状态?

C# 加密流是否可以使基流保持打开状态?,c#,stream,objectdisposedexception,C#,Stream,Objectdisposedexception,我创建了一个MemoryStream,将其传递给CryptoStream进行写入。我想让加密流加密,然后让内存流打开,让我读入其他内容。但是只要加密流被处理,它也会处理内存流 CryptoStream能否以某种方式保持基本MemoryStream打开 using (MemoryStream scratch = new MemoryStream()) { using (AesManaged aes = new AesManaged()) { // <snip&

我创建了一个
MemoryStream
,将其传递给
CryptoStream
进行写入。我想让
加密流
加密,然后让
内存流
打开,让我读入其他内容。但是只要
加密流
被处理,它也会处理
内存流

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);
}
使用(MemoryStream scratch=new MemoryStream())
{
使用(AesManaged aes=新AesManaged())
{
// 
//设置一些aes参数,包括Key、IV等。
// 
ICryptoTransform encryptor=aes.CreateEncryptor();
使用(CryptoStream myCryptoStream=新的CryptoStream(scratch、encryptor、CryptoStreamMode.Write))
{
写入(someByteArray,0,someByteArray.Length);
}
}
//在这里,我仍然在MemoryStream块中,所以我希望
//MemoryStream仍然可用。
scratch.Position=0;//抛出ObjectDisposedException
byte[]scratchBytes=新字节[scratch.Length];
scratch.Read(scratchBytes,0,scratchBytes.Length);
返回Convert.ToBase64String(scratchBytes);
}

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

一旦您完成了对流的所有操作,您就可以在最后的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();
}
MemoryStream scratch=null;
aes=空;
CryptoStream myCryptoStream=null;
尝试
{
scratch=新内存流();
aes=新aes管理();
// 
//设置一些aes参数,包括Key、IV等。
// 
ICryptoTransform encryptor=aes.CreateEncryptor();
myCryptoStream=新的加密流(scratch、encryptor、CryptoStreamMode.Write);
写入(someByteArray,0,someByteArray.Length);
//清除数据,使其完全写入底层流。
myCryptoStream.FlushFinalBlock();
划痕位置=0;
byte[]scratchBytes=新字节[scratch.Length];
scratch.Read(scratchBytes,0,scratchBytes.Length);
返回Convert.ToBase64String(scratchBytes);
}
最后
{
//按相反顺序处理我们创建的所有可处理对象。
if(myCryptoStream!=null)
myCryptoStream.Dispose();
如果(aes!=null)
aes.Dispose();
if(scratch!=null)
scratch.Dispose();
}

事实证明,不需要将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);
        }
    }
}
使用(MemoryStream scratch=new MemoryStream())
{
使用(AesManaged aes=新AesManaged())
{
// 
//设置一些aes参数,包括Key、IV等。
// 
ICryptoTransform encryptor=aes.CreateEncryptor();
使用(CryptoStream myCryptoStream=新的CryptoStream(scratch、encryptor、CryptoStreamMode.Write))
{
写入(someByteArray,0,someByteArray.Length);
myCryptoStream.FlushFinalBlock();
scratch.Flush();//不确定这是否必要
byte[]scratchBytes=scratch.ToArray();
返回Convert.ToBase64String(scratchBytes);
}
}
}

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

我的简单解决方案:

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 );
    }
}

从.NET 4.7.2开始,还有第二个构造函数,它添加了一个名为
leaveOpen
的bool参数。如果该值设置为true,则
加密流
的dispose方法将不会对基础流调用dispose

,没有
leaveOpen
参数的另一个构造函数将参数转发给
leaveOpen
设置为
false
的新构造函数



对于给我A—1的人,我认为我的回答是“没有用的”,以保证A- 1吗?如果我的帖子中有不正确的信息,请通知我,以便我可以更正或删除它。我想,编写代码的方式是内部
try finally
是不必要的。我会移除它。我能想到的另一件事是,
aes
scratch
myCryptoStream
之前得到处理。我也会纠正这一点。如果您想编写一个方法,在基本流被加密后返回基本流,并在返回基本流之前处理加密流,该怎么办?处理加密流是否重要?或者,在处理完基流后只处理它就可以了吗?向下投票:不解决如何从使用CryptoStream的方法返回基流CryptoStream dispose方法仍将处理底层流。你仍然会被复制。你只是把它推迟到最后一个街区。下面是使用.NET 4.7.2版新构造函数重载的正确答案。
scrach.Flush()
确实是不必要的,“重写Stream.Flush方法,以便不执行任何操作。”为什么要首先使用streams?只需对输入字节调用encryptor.TransformFinalBlock。流对于增量加密/解密最为有用,但当您同时拥有完整的可用数据时就没有了。它可以工作,但我有一个问题:正如MSDN提到的
disposing Type:System.Boolean true可以释放托管和非托管资源;如果为false,则仅释放非托管资源
。但正如我所知,流对象是非托管对象