C# 热身:流 (V) 下一页
对于重写的方法这里不再重复说明,大家可以参考我写的第一篇
以下是memoryStream独有的方法
virtual byte[] GetBuffer()
这个方法使用时需要小心,因为这个方法返回无符号字节数组,也就是说,即使我只输入几个字符例如”HellowWorld”我们只希望返回11个数据就行,
可是这个方法会把整个缓冲区的数据,包括那些已经分配但是实际上没有用到的字节数据都返回出来,如果想启用这个方法那必须使用上面最后一个构
造函数,将publiclyVisible属性设置成true就行,这也是上面那个构造函数的作用所在
virtual void WriteTo(Stream stream)
这个方法的目的其实在本文开始时讨论性能问题时已经指出,memoryStream常用起中间流的作用,
所以读写在处理完后将内存流写入其他流中
简单示例 XmlWriter中使用MemoryStream
/// <summary>
/// 演示在xmlWriter中使用MemoryStream
/// </summary>
public static void UseMemoryStreamInXMLWriter()
{
MemoryStream ms = new MemoryStream();
using (ms)
{
//定义一个XMLWriter
using (XmlWriter writer = XmlWriter.Create(ms))
{
//写入xml头
writer.WriteStartDocument(true);
//写入一个元素
writer.WriteStartElement("Content");
//为这个元素新增一个test属性
writer.WriteStartAttribute("test");
//设置test属性的值
writer.WriteValue("逆时针的风");
//释放缓冲,这里可以不用释放,但是在实际项目中可能要考虑部分释放对性能带来的提升
writer.Flush();
Console.WriteLine("此时内存使用量为:{2}KB,该MemoryStream的已经使用的容量为{0}byte,默认容量为{1}byte",
Math.Round((double)ms.Length, 4), ms.Capacity,GC.GetTotalMemory(false)/1024);
Console.WriteLine("重新定位前MemoryStream所在的位置是{0}",ms.Position);
//将流中所在的当前位置往后移动7位,相当于空格
ms.Seek(7, SeekOrigin.Current);
Console.WriteLine("重新定位后MemoryStream所在的位置是{0}", ms.Position);
//如果将流所在的位置设置为如下所示的位置则xml文件会被打乱
//ms.Position = 0;
writer.WriteStartElement("Content2");
writer.WriteStartAttribute("testInner");
writer.WriteValue("逆时针的风Inner");
writer.WriteEndElement();
writer.WriteEndElement();
//再次释放
writer.Flush();
Console.WriteLine("此时内存使用量为:{2}KB,该MemoryStream的已经使用的容量为{0}byte,默认容量为{1}byte",
Math.Round((double)ms.Length, 4), ms.Capacity, GC.GetTotalMemory(false)/1024);
//建立一个FileStream 文件创建目的地是d:test.xml
FileStream fs = new FileStream(@"d:test.xml",FileMode.OpenOrCreate);
using (fs)
{
//将内存流注入FileStream
ms.WriteTo(fs);
if(ms.CanWrite)
//释放缓冲区
fs.Flush();
}
}
}
}
输出结果:
简单示例:自定义一个处理图片的HttpHandler
有时项目里我们必须将图片进行一定的操作,例如水印,下载等,为了方便和管理我们可以自定义一个HttpHander 来负责这些工作
后台:
public class ImageHandler : IHttpHandler
{
#region IHttpHandler Members
public bool IsReusable
{
get { return true; }
}
/// <summary>
/// 实现IHTTPHandler后必须实现的方法
/// </summary>
/// <param name="context">HttpContext上下文</param>
public void ProcessRequest(HttpContext context)
{
context.Response.Clear();
//得到图片名
var imageName = context.Request["ImageName"] == null ? "逆时针的风"
: context.Request["ImageName"].ToString();
//得到图片ID,这里只是演示,实际项目中不是这么做的
var id = context.Request["Id"] == null ? "01"
: context.Request["Id"].ToString();
//得到图片地址
var stringFilePath = context.Server.MapPath(string.Format("~/Image/{0}{1}.jpg", imageName, id));
//声明一个FileStream用来将图片暂时放入流中
FileStream stream = new FileStream(stringFilePath, FileMode.Open);
using (stream)
{
//透过GetImageFromStream方法将图片放入byte数组中
byte[] imageBytes = this.GetImageFromStream(stream,context);
//上下文确定写到客户短时的文件类型
context.Response.ContentType = "image/jpeg";
//上下文将imageBytes中的数据写到前段
context.Response.BinaryWrite(imageBytes);
stream.Close();
}
}
/// <summary>
/// 将流中的图片信息放入byte数组后返回该数组
/// </summary>
/// <param name="stream">文件流</param>
/// <param name="context">上下文</param>
/// <returns></returns>
private byte[] GetImageFromStream(FileStream stream, HttpContext context)
{
//通过stream得到Image
Image image = Image.FromStream(stream);
//加上水印
image = SetWaterImage(image, context);
//得到一个ms对象
MemoryStream ms = new MemoryStream();
using (ms)
{
//将图片保存至内存流
image.Save(ms, ImageFormat.Jpeg);
byte[] imageBytes = new byte[ms.Length];
ms.Position = 0;
//通过内存流读取到imageBytes
ms.Read(imageBytes, 0, imageBytes.Length);
ms.Close();
//返回imageBytes
return imageBytes;
}
}
/// <summary>
/// 为图片加上水印,这个方法不用在意,只是演示,所以没加透明度
/// 下次再加上吧
/// </summary>
/// <param name="image">需要加水印的图片</param>
/// <param name="context">上下文</param>
/// <returns></returns>
private Image SetWaterImage(Image image,HttpContext context)
{
Graphics graphics = Graphics.FromImage(image);
Image waterImage = Image.FromFile(context.Server.MapPath("~/Image/逆时针的风01.jpg"));
//在大图右下角画上水印图就行
graphics.DrawImage(waterImage,
new Point {
X = image.Size.Width - waterImage.Size.Width,
Y = image.Size.Height - waterImage.Size.Height
});
return image;
}
#endregion
}
别忘了还要在Web.Config中进行配置,别忘记verb和path属性,否则会报错
<httpHandlers>
<add type="ImageHandler.ImageHandler,ImageHandler" verb="*" path="ImageHandler.apsx"/>
</httpHandlers>
这样前台便能使用了
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
<h2>
About </h2>
<p>
Put content here. <asp:Image runat="server" ImageUrl="ImageHandler.apsx?ImageName=逆时针的风&Id=02" />
</p></asp:Content>
输出结果
本章总结
本章主要介绍了MemoryStream 的一些概念,异常,结构,包括如何使用,如何解决一些异常等
上一篇: 设计模式 - 装饰器
下一篇: 从过去学习:MySQL 存储引擎入门