none
出现了System.OutOfMemoryException异常 RRS feed

  • 问题

  • 问题说明:一.Winform程序,本机运行.
    二.数据库字段为Image,
    三.Image字段中存了一个约700M的档案吧.
    四.现在需要取出Image的字段了,代码如下:
    五.在数据库中已进行了很长的超时设定.

    SqlConnection cn=new SqlConnection(cnString.cnStr());
            if(cn.State==ConnectionState.Closed) cn.Open();
            if(fileid=="") return;
            string    selstr="select files,filename from soft_savefiles where filesid="+fileid;//fileid是文档编号
            SqlCommand cmd=new SqlCommand(selstr,cn);
            cmd.CommandTimeout = 1200;
            SqlDataReader dr=cmd.ExecuteReader();
            while(dr.Read())
            {
                byte[] file=(byte[])dr[0];//这里错了,说什么'要创建数组,请确认大小',500M以下的取出也没有问题呀?
              
                  
                    FileStream fs   = new FileStream(@"C:\"+filename, FileMode.CreateNew);
                    BinaryWriter bw = new BinaryWriter(fs);
                    bw.Write(file, 0, file.Length);
                    bw.Close();
                    fs.Close();
                    fs.Dispose();
            }
    出现了System.OutOfMemoryException异常
    2009年7月10日 5:53

答案

  • SqlConnection cn=new SqlConnection(cnString.cnStr());
            if(cn.State==ConnectionState.Closed) cn.Open();
            if(fileid=="") return;
            string    selstr="select files,filename from soft_savefiles where filesid="+fileid;//fileid是文档编号
            SqlCommand cmd=new SqlCommand(selstr,cn);
            cmd.CommandTimeout = 1200;
            SqlDataReader dr=cmd.ExecuteReader();
            while(dr.Read())
            {
                   FileStream fs   = new FileStream(@"C:\"+filename, FileMode.CreateNew);
                 // BinaryWriter bw = new BinaryWriter(fs);其实不大需要
    
                   byte[] buf=new byte[1023]
                   int readbyte=-1,index=0;
                   for ( ;readbyte!=0;)
                   {
                       readbyte=dr.GetBytes(0,index,buf,0,1024);
                       index=index +readbyte;
                       fs.write(buf,0,readbyte );
                   }
               
                   
    
                
                    bw.Write(file, 0, file.Length);
                    bw.Close();
                    fs.Close();
                    fs.Dispose();
            }
    
    您可以做类似的修改
    这都是按照印象写的  可能有点小出入



    答案900, 目标五颗星
    • 已标记为答案 zjh111 2009年7月11日 9:01
    2009年7月10日 6:39
    版主
  • 好象少了一个什么关键语句,没有用Dr读取的字段呀??

    并没有少,已经体现在dr.GetBytes(0,index,buf,0,1024);
    各参数含义,请参考韦恩卑鄙上一封的解释。
    • 已标记为答案 zjh111 2009年7月11日 9:00
    2009年7月10日 15:16

全部回复

  • 我不知道,对大字段的读取,可不可以分字节一段一段地读出并存储为文件.
    读入到Image字段也可以用相同的方法...
    不知C#能不能实现.............
    2009年7月10日 6:26
  •  SqlDataReader 可以直接按照流读取某个字段 

    public override long GetBytes(int i, long dataIndex, byte[] buffer, int bufferIndex, int length)
        Member of System.Data.SqlClient.SqlDataReader

    Summary:
    Reads a stream of bytes from the specified column offset into the buffer an array starting at the given buffer offset.

    Parameters:
    i: The zero-based column ordinal.
    dataIndex: The index within the field from which to begin the read operation.
    buffer: The buffer into which to read the stream of bytes.
    bufferIndex: The index within the buffer where the write operation is to start.
    length: The maximum length to copy into the buffer.

    Returns:
    The actual number of bytes read.


    答案900, 目标五颗星
    2009年7月10日 6:31
    版主
  • SqlConnection cn=new SqlConnection(cnString.cnStr());
            if(cn.State==ConnectionState.Closed) cn.Open();
            if(fileid=="") return;
            string    selstr="select files,filename from soft_savefiles where filesid="+fileid;//fileid是文档编号
            SqlCommand cmd=new SqlCommand(selstr,cn);
            cmd.CommandTimeout = 1200;
            SqlDataReader dr=cmd.ExecuteReader();
            while(dr.Read())
            {
                   FileStream fs   = new FileStream(@"C:\"+filename, FileMode.CreateNew);
                 // BinaryWriter bw = new BinaryWriter(fs);其实不大需要
    
                   byte[] buf=new byte[1023]
                   int readbyte=-1,index=0;
                   for ( ;readbyte!=0;)
                   {
                       readbyte=dr.GetBytes(0,index,buf,0,1024);
                       index=index +readbyte;
                       fs.write(buf,0,readbyte );
                   }
               
                   
    
                
                    bw.Write(file, 0, file.Length);
                    bw.Close();
                    fs.Close();
                    fs.Dispose();
            }
    
    您可以做类似的修改
    这都是按照印象写的  可能有点小出入



    答案900, 目标五颗星
    • 已标记为答案 zjh111 2009年7月11日 9:01
    2009年7月10日 6:39
    版主
  • 还有一种办法



    dr.GetSqlBytes (0).Stream  直接获取读取此字段的流   性能应该差不多  但是这样做流的对拷  应该比较容易写算法了

    答案900, 目标五颗星
    2009年7月10日 6:45
    版主
  • 好象少了一个什么关键语句,没有用Dr读取的字段呀??
    2009年7月10日 10:32
  • Hi,
      你数据设计为什么不考虑把这种大数据对象存贮在数据库外的介质上呢。
    这种操作带来的开销太大,性能也是问题。
    Frank.Xu Lei--谦卑若愚,好学若饥
    专注于.NET平台下分布式应用系统开发和企业应用系统集成
    Focus on Distributed Applications Development and EAI based on .NET
    老徐的博客:http://frank_xl.cnblogs.com
    2009年7月10日 11:33
    版主
  • 这是档案存储呀,很长很长一段时间才存取一次,所以就这么作了,如果是文件的话,客户会不小心删了怎么办??
    如象SQl2008有文件存储,也不知好不好
    2009年7月10日 13:42
  • 这是档案存储呀,很长很长一段时间才存取一次,所以就这么作了,如果是文件的话,客户会不小心删了怎么办??
    如象SQl2008有文件存储,也不知好不好

    客户端能不能删除,是你权限控制的问题啊,呵呵,而且你也可以备份啊。2008的文件存储没接触过,2005其实已经提供了大数据对下个的存储优化,但是这个毕竟很大的文件,读取是要花费不少时间的
    Frank.Xu Lei--谦卑若愚,好学若饥
    专注于.NET平台下分布式应用系统开发和企业应用系统集成
    Focus on Distributed Applications Development and EAI based on .NET
    老徐的博客:http://frank_xl.cnblogs.com
    2009年7月10日 14:02
    版主
  • 同意Frank.Xu Lei的观点,毕竟是700M,相信以后还会更大,最好还是放在Sql以外做存储,毕竟Sql是为了关系型数据设计的。不像Sharepoint或Domino是文档型数据库。
    如果担心被删除,可以采用操作系统的权限控制来解决。
    2009年7月10日 14:28
  • 客户已经存储进去了,不可能存了几年的资料让它丢失吧!!!
    大家帮一把,给个代码吧....................以后设计就可以不会Image存储大文件了
    2009年7月10日 14:44
  • 好象少了一个什么关键语句,没有用Dr读取的字段呀??

    并没有少,已经体现在dr.GetBytes(0,index,buf,0,1024);
    各参数含义,请参考韦恩卑鄙上一封的解释。
    • 已标记为答案 zjh111 2009年7月11日 9:00
    2009年7月10日 15:16
  • 我的天,又错了
    代码如下:

     SqlDataReader dr = cmd.ExecuteReader();
                #region 回贴B           
                while (dr.Read())
                {
                    FileStream fs = new FileStream(@"C:\x.rar" , FileMode.CreateNew);
                    //BinaryWriter bw = new BinaryWriter(fs);//其实不大需要

                    byte[] buf = new byte[1024];
                    long readbyte = -1;
                    long index = 0;
                    for (; readbyte != 0; )
                    {
                        readbyte = dr.GetBytes(0, index, buf, 0, 1024);//这里又出现相同的泄漏了?????
                        index = index + readbyte;
                        fs.Write(buf, 0, (int)readbyte);//readbyte是Long不是INT
                    }
                    //bw.Write(file, 0, file.Length);
                    //bw.Close();
                    fs.Close();
                    fs.Dispose();
                }
                #endregion
    2009年7月10日 16:27