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,则仅释放非托管资源
。但正如我所知,流对象是非托管对象