我创建了一个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);
}
答案 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
的新构造函数。
答案 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 );
}
}