由Stream.Position问题而引发的思考

简介:
Web开发中的文件上传功能一直以来都是一个比较棘手的问题,特别是在开发Ajax网站时,面对功能复杂的页面元素,实现页面无刷新的文件上传功能就变得更加复杂。我在 http://www.cnblogs.com/jaxu/archive/2009/05/19/1459796.html 一文中介绍过如何通过页面中隐藏的iFrame提交表单达到文件的上传,而且不刷新当页中的Form,模拟页面的无刷新文件上传功能。而且一般情况下,我们在服务端会这样来处理要上传的文件。
复制代码
private  List < ImageEntity >  GetUploadImages()
{
    List
< ImageEntity >  images  =   new  List < ImageEntity > ();
    HttpFileCollection files 
=  Request.Files;
    
int  fileLen;
    ImageEntity image 
=   null ;

    
if  (files  !=   null   &&  files.Count  >   0 )
    {
        
for  ( int  i  =   0 ; i  <  files.Count; i ++ )
        {
            
if  (files[i].FileName.Length  !=   0 )
            {
                
try
                {
                    fileLen 
=  files[i].ContentLength;
                    Byte[] bytes 
=   new  Byte[fileLen];
                    stream.Read(bytes, 
0 , fileLen);

                    image 
=   new  ImageEntity();
                    image.Type 
=  files[i].ContentType;
                    image.ImageBlob 
=  bytes;
                    image.Title 
=  Path.GetFileName(files[i].FileName);
                    images.Add(image);
                }
                
catch  { }
            }
        }
    }

    
return  images;
}
复制代码
    这是一个得到客户端上传的图片文件的示例代码,其中的ImageEntity是一个Image的实体类,我们可以通过该实体类描述的信息将图片存储在数据库中(或者存储在服务器磁盘上)。
复制代码
public   class  ImageEntity
{
    
public  ImageEntity()
    {
    }

    
public  ImageEntity( string  title, Byte[] imageBlob,  string  type)
    {
        Title 
=  title;
        ImageBlob 
=  imageBlob;
        Type 
=  type;
    }

    
public   string  Title {  get set ; }
    
public   string  Type {  get set ; }
    
public  Byte[] ImageBlob {  get set ; }
}
复制代码

    这么使用是没有问题的!当我们上传图片时,页面通过Post方法提交到服务端,服务端构造一个和图片字节大小相同的byte数组,通过HttpPostedFile的InputStream属性得到一个System.IO.Stream对象,然后使用该对象的Read方法将图片数据流读到byte数组中。这个过程页面是需要回传的,并且下一次用户上传图片时Stream对象会被重新构造,然后重新填充byte数组。

    不过在一次MOSS开发中我偶然地发现使用该方式上传图片时,保存图片到数据库没有出现问题,当从数据库中读取图片时却显示了一个红色的叉,表示图片不可用或加载失败。仔细查看了一下数据库中的数据,除了保存图片二进制数据的字段显示为<Binary data>外,其余字段的数据都很正常,没有发现什么异常情况,调试了一下程序,图片上传和保存的过程中并没有抛出任何异常,一切都很顺利,但就是在读取图片的时候页面上无法正常加载图片。

    一开始我就感觉这个问题很奇怪,看来问题应该是出在上传图片时图片的二进制数据获取得不正确或不完整,我再次调试跟踪了一下代码,发现在上传的过程中byte数组中的值始终都是0,即便是在通过Stream.Read方法填充数据之后也是如此。这到底是为什么?难道我用错对象了?查了一下MSDN,发现上面给出的示例基本上也是通过这种方法得到要上传的文件并通过Stream.Read方法填充byte数组的,MSDN的示例代码肯定是不会有错误的,那错误到底在哪里呢?我开始迷惑了...

    仔细搜了搜Google,其中有一位朋友给出的帮助对我很有用,他建议在使用Stream.Read方法填充byte数组前先判断一下Stream.Position的值是否为0,如果不为0就先将它置为0,然后再进行byte数组的填充。不过我先是想到每次页面在上传文件时所构造的Stream对象都是新的(因为页面会PostBack回来),我并没有在程序的任何地方缓存Stream对象,既然Stream对象是新的,那么Position属性的值肯定就是0啦。我抱着半信半疑的心态试了试这位朋友介绍的方法,果然奏效了,看来Stream对象真的是在某个地方被缓存了,或者说在前一次文件上传之后Stream对象没有被完全释放。于是我修改了上面的那个得到上传图片的方法。

复制代码
private  List < ImageEntity >  GetUploadImages()
{
    List
< ImageEntity >  images  =   new  List < ImageEntity > ();
    HttpFileCollection files 
=  Request.Files;
    
int  fileLen;
    ImageEntity image 
=   null ;

    
if  (files  !=   null   &&  files.Count  >   0 )
    {
        
for  ( int  i  =   0 ; i  <  files.Count; i ++ )
        {
            
if  (files[i].FileName.Length  !=   0 )
            {
                
try
                {
                    fileLen 
=  files[i].ContentLength;
                    Byte[] bytes 
=   new  Byte[fileLen];
                    
using  (Stream stream  =  files[i].InputStream)
                    {
                        stream.Position 
=   0 ;
                        stream.Read(bytes, 
0 , fileLen);
                    }

                    image 
=   new  ImageEntity();
                    image.Type 
=  files[i].ContentType;
                    image.ImageBlob 
=  bytes;
                    image.Title 
=  Path.GetFileName(files[i].FileName);
                    images.Add(image);
                }
                
catch  { }
            }
        }
    }

    
return  images;
}
复制代码

    因为我是在MOSS平台上开发的,与普通的ASP.NET项目就有很多的不同,有可能会受到很多MOSS本身的东西影响,例如缓存机制等。但不管怎样,涉及到像Stream这样的对象,在使用之后最好都让它立即释放,因为即使Stream不被缓存,它也有可能长时间占用内存而消耗掉很多的服务器资源。建议在Using语句中使用Stream,并且在使用Read方法填充byte数组前重置Position为0,这样可以确保byte数组被正确填充,从而保证可以得到正确的文件数据。


本文转自Jaxu博客园博客,原文链接:http://www.cnblogs.com/jaxu/archive/2009/05/19/1460250.html,如需转载请自行联系原作者


相关文章
|
24天前
|
存储 JavaScript 网络协议
Stream
【10月更文挑战第22天】
22 1
|
2月前
|
Web App开发 前端开发 测试技术
你可能对position和z-index有一些误解
该文章深入解析了CSS中`position`属性的各个取值(static、relative、absolute、fixed、sticky)的使用场景及`z-index`在层叠上下文中如何确定元素的堆叠顺序,并通过具体例子展示了这些属性的实际应用效果。
你可能对position和z-index有一些误解
|
3月前
|
Android开发
解决RenderUiKitView object was given an infinite size during layout.
解决RenderUiKitView object was given an infinite size during layout.
35 3
|
5月前
|
Java
java中Stream流中的forEach、filter、map、count、limit、skip、concat
java中Stream流中的forEach、filter、map、count、limit、skip、concat
164 0
|
11月前
|
Java 测试技术 Maven
stream-query
stream-query
108 0
|
12月前
can't do nonzero end-relative seeks
can't do nonzero end-relative seeks
32 0
|
索引
av_find_best_stream
av_find_best_stream
139 0
av_find_best_stream
ByteBuffer中的flip()、clear()、compact()
ByteBuffer中的flip()、clear()、compact()
148 0
ByteBuffer中的flip()、clear()、compact()
|
前端开发 容器
你真的了解position吗?
你真的了解position吗?