zoukankan      html  css  js  c++  java
  • Oracle中BLOB字段存储4GB以下视频数据的方法

      很长时间没亲自写写东西了,只是收集转载了一些好资料,其实,真正静下心总结一下,可以写的知识点很多。与困难做斗争,挑战技术难关,总会有些感受心得的。

      今天想和网友分享一下“Oracle中BLOB大字段如何读写视频数据”,这个话题起因是我在使用ORACLE备份数据时,误删了数据库实例的控制文件,导致项目数据需要重新入库。也就是我在弥补这个错误时,发现之前的数据入库功能,都没有把200M以上的视频数据导入ORACLE的BLOB字段里,也就是之前的写入BLOB字段数据的方法失效了。这是个惊人的发现,我发现因为这个程序BUG我遗漏掉近300G的视频数据,某些单个视频文件数据量达到3.6G。

      我研究基于ORACLE Text的全文检索功能,开始接触ORACLE的BLOB字段,3年多了,自认为已经熟知BLOB字段的操作。但这次的难题迫使我更深入的认识ORACLE的BLOB字段。

      BLOB字段能以二进制形式存放4G数据,200M的视频数据当然应该没问题,可以出错了?!原来的方法会报“Out of memory”错误,PLSQL Developer工具导入大视频数据,同样会报“Out of memory”错误。3.6G的视频数据又该如何导入?原来写入大字段的方法,导入一般的图片和文档一点问题没有。

            /// <summary>
            
    /// 写大字段内容
            
    /// (新方法,2010.2.4)
            
    /// </summary>
            
    /// <param name="pDbConn"></param>
            
    /// <param name="strTable"></param>
            
    /// <param name="strBlobField"></param>
            
    /// <param name="strFile"></param>
            
    /// <param name="strWhereClause"></param>
            
    /// <returns></returns>
            public bool WriteBlobField(System.Data.OleDb.OleDbConnection pDbConn,
                
    string strTable,
                
    string strBlobField,
                
    string strFile,
                
    string strWhereClause)
            {
                
    if (strWhereClause == "")
                {
                    
    return false;
                }
                
    try
                {
                    
    string strSQL = "UPDATE " + strTable + " SET " + strBlobField + " =:blob WHERE " + strWhereClause;

                    OleDbCommand cmd 
    = new OleDbCommand(strSQL, pDbConn);
                    
    //无需说明类型
                    
    //cmd.Parameters.Add(new OleDbParameter("blob", SqlDbType.VarBinary));
                    
    // cmd.Parameters.AddWithValue("blob", SqlDbType.Binary);
                    FileInfo fileInfo = new FileInfo(strFile);

                    FileStream fsBlob 
    = fileInfo.OpenRead();// new FileStream(strFile, FileMode.Open,FileAccess.Read);
                    byte[] dataBlob = new byte[fsBlob.Length];//问题1所在
                    fsBlob.Read(dataBlob, 
    0System.Convert.ToInt32(fsBlob.Length));//问题2所在
                    fsBlob.Close();
                    
    //采用新的方法,AddWithValue();
                    cmd.Parameters.AddWithValue("blob", dataBlob);
                    
    //cmd.Parameters["blob"].Value = dataBlob;
                    int result = cmd.ExecuteNonQuery();
                    
    if (result < 1)
                    {
                        
    return false;
                    }
                }
                
    catch (Exception ex)
                {
                    
    //   MessageBox.Show(ex.Message, "写数据", MessageBoxButtons.OK);
                    return false;
                }

                
    return true;
            }

                
    /// <summary>
                
    /// 将字符串写成大字段内容
                   
    /// (2010.2.4 修改)
                
    /// </summary>
                
    /// <param name="pDbConn"></param>
                
    /// <param name="strTable"></param>
                
    /// <param name="strBlobField"></param>
                
    /// <param name="strBlobContent"></param>
                
    /// <param name="strWhereClause"></param>
                
    /// <returns></returns>
                public bool WriteBlobField2(System.Data.OleDb.OleDbConnection pDbConn,
                              
    string strTable,
                             
    string strBlobField,
                             
    string strBlobContent,
                             
    string strWhereClause)
                {
                    
    if (strWhereClause == "")
                    {
                        
    return false;
                    }

                    
    try
                    {
                        
    string strSQL = "UPDATE " + strTable + " SET " + strBlobField + " =:blob " +
                            
    "WHERE " + strWhereClause;

                        OleDbCommand cmd 
    = new OleDbCommand(strSQL, pDbConn);
                        cmd.Parameters.Add(strBlobField, SqlDbType.Binary);
                        
    //    byte[] dataBlob = new byte[strBlobContent.Length];
                        byte[] dataBlob = System.Text.Encoding.Default.GetBytes(strBlobContent);
                        cmd.Parameters[
    "blob"].Value = dataBlob;
                        
    int result = cmd.ExecuteNonQuery();
                        
    if (result < 1)
                        {
                            
    return false;
                        }
                    }
                    
    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message, 
    "写数据", MessageBoxButtons.OK);
                        
    return false;
                    }

                    
    return true;
                }

     问题1:无法一次性开辟足够大空间(如1G),写入大视频时,会导致报内存不足。

     问题2:System.Convert.ToInt32()会使3G的视频时,会报类型转换失败,数值值过大。

      上面两个问题在网络中所有的方法中都普遍存在的,都会导致无法导入700M以上的视频数据。

      OLEDB方法对ORCLE 8以后的大字段操作不在支持,我在解决问题的过程中转向了OracleClient命名空间下的方法来操作BLOB大字段,主要参考微软官方http://msdn.microsoft.com/zh-cn/library/cydxhzhz(v=VS.90).aspx和博客园中的http://www.cnblogs.com/zhengmaoch/archive/2005/08/10/212014.html。这两份资料对我解决500M以下数据量的视频很有帮助,但是1G甚至是3G以上视频数据是无法解决的。上面两处使用了事务处理在导500M以上数据时,会报“ORA-22297: warning: Open LOBs exist at transaction commit time ”错误,主要因为提交事务时数据文件没有读完。

      经过试验和参考http://msdn.microsoft.com/en-us/library/system.io.filestream.read.aspx方法,终于完全解决上面两个问题,实现大视频量数据导入BLOB字段。

            /// <summary>
            
    /// 2010.10.22
            
    /// 读取视频数据进入ORACLE大字段中
            
    /// </summary>
            
    /// <param name="fileToUpload"></param>
            
    /// <param name="uploadSQL"></param>
            
    /// <returns></returns>
            public bool OracleUpload(string fileToUpload, string uploadSQL)
            {
                
    /*
                 * Get Connected
                 
    */
                
    string connection = strConn;
                OracleConnection conn;
                conn 
    = new OracleConnection(connection);
                conn.Open();
                OracleCommand cmd 
    = new OracleCommand(uploadSQL, conn);
                OracleTransaction transaction 
    = conn.BeginTransaction();
                cmd.Transaction 
    = transaction;
                OracleDataReader reader 
    = cmd.ExecuteReader();
                
    using (reader)
                {
                    
    try
                    {
                        reader.Read();
                        OracleLob tmpBlob 
    = reader.GetOracleLob(4);
                        reader.Close();
                        FileStream fsBlob 
    = new FileStream(fileToUpload, FileMode.OpenOrCreate, FileAccess.Read);
                        
    //BinaryReader br = new BinaryReader(fs);
                        tmpBlob.BeginBatch(OracleLobOpenMode.ReadWrite);
                        
    long length = fsBlob.Length;

                        
    int numBytesToRead = System.Convert.ToInt32(length / 10);//解决问题2
                        int numBytesRead = 0;
                        
    int n;
                        
    byte[] Buffer = new byte[numBytesToRead];
                        
    //2010.10.25  修改加 将文件分为10块 防止文件为3.3G以上
                         
    //解决问题1
                        for (int i = 0; i < 9; i++
                        {
                            
                            n 
    = 0;
                           
    // numBytesToRead = length / 5;
                            Buffer = new byte[numBytesToRead]; 
                            numBytesRead 
    = 0;
                            
    while ((n = fsBlob.Read(Buffer, numBytesRead, numBytesToRead)) > 0)
                            {
                                numBytesRead 
    += n;
                                numBytesToRead 
    -= n;
                            }
                            numBytesToRead 
    = System.Convert.ToInt32(length / 10);
                            tmpBlob.Write(Buffer, 
    0, numBytesToRead);
                        }

           
                        numBytesToRead 
    = System.Convert.ToInt32(length / 10+ length % 10);
                        numBytesRead 
    = 0;
                        n 
    = 0;
                        
    int tmpLength = numBytesToRead;
                        
    byte[] Buffer2 = new byte[tmpLength];
                        
    while ((n = fsBlob.Read(Buffer2, numBytesRead, numBytesToRead)) > 0)
                        {
                            numBytesRead 
    += n;
                            numBytesToRead 
    -= n;
                        }
                        
    //numBytesToRead = tmpLength;
                        tmpBlob.Write(Buffer2, 0, tmpLength);

                        fsBlob.Close();
                        tmpBlob.EndBatch();
                        cmd.Parameters.Clear();
                        Buffer 
    = null;    
                    }
                    
    catch(Exception ex)
                    {
                        MessageBox.Show(
    "出错:"+ex.Message);
                        
    //关闭
                        reader.Close();
                        transaction.Commit();
                        conn.Close();
                        
    return false;
                    }
                }

                reader.Close();
                transaction.Commit();
                conn.Close();
                
    return true;
            }

       上面的方法完全能处理4G以下的视频数据的导入问题,已经经过验证的。PLSQL Developer工具同样无法读取BLOB字段中的大数据量的视频,如需读取请详细参照http://www.cnblogs.com/wuhenke/archive/2010/10/25/1860752.html

            /// <summary>
            
    /// 从数据库中读出大字段到文件中
            
    /// </summary>
            
    /// <param name="uploadSQL"></param>
            
    /// <returns></returns>
            public bool OracleRead(string uploadSQL)
            {
                
    string connection = strConn;
                OracleConnection conn;
                conn 
    = new OracleConnection(connection);
                conn.Open();


                OracleCommand cmd 
    = new OracleCommand(uploadSQL, conn);
                
    long readStartByte = 0;//从BLOB数据体的何处开始读取数据
                int hopeReadSize = 1024//希望每次从BLOB数据体中读取数据的大小
                long realReadSize = 0;//每次实际从BLOB数据体中读取数据的大小
                
    //CommandBehavior.SequentialAccess将使OracleDataReader以流的方式加载BLOB数据
                string filename = "F:\\Test"+DateTime.Now.Day+DateTime.Now.Minute+DateTime.Now.Second+".avi";
                OracleDataReader dr 
    = cmd.ExecuteReader(CommandBehavior.SequentialAccess);
                
    while (dr.Read())
                {
                    FileStream fs 
    = new FileStream(filename, FileMode.Create);
                    
    byte[] buffer = new byte[hopeReadSize];
                    realReadSize 
    = dr.GetBytes(0, readStartByte, buffer, 0, hopeReadSize);
                    
    //循环,每次读取1024byte大小,并将这些字节写入流中
                    while ((int)realReadSize == hopeReadSize)
                    {
                        fs.Write(buffer, 
    0, hopeReadSize);
                        readStartByte 
    += realReadSize;
                        realReadSize 
    = dr.GetBytes(0, readStartByte, buffer, 0, hopeReadSize);
                    }
                    
    //读取BLOB数据体最后剩余的小于1024byte大小的数据,并将这些字节写入流中
                    realReadSize = dr.GetBytes(0, readStartByte, buffer, 0, hopeReadSize);
                    fs.Write(buffer, 
    0, (int)realReadSize);
                }           
                
    //transaction.Commit();
                conn.Close();
                    
    return true;
            }

    参考资料:

    http://msdn.microsoft.com/zh-cn/library/cydxhzhz(v=VS.90).aspx

    http://www.cnblogs.com/zhengmaoch/archive/2005/08/10/212014.html

    http://msdn.microsoft.com/en-us/library/dyh7k75y(vs.71).aspx

    http://www.pczpg.com/a/2010/0719/14962.html

    http://msdn.microsoft.com/en-us/library/system.io.filestream.read.aspx

    http://www.csharp-examples.net/filestream-read-file/

    http://blog.csdn.net/lonet/archive/2010/03/03/5342386.aspx

    本博客声明:本人的技术探索过程中,得到了国信司南公司方面支持。今后,本人博客里的所有技术探索成果将归“无痕客”、“国信司南”和“博客园”三方共同所有,原创作品如需转载,请注明本博客声明。

     

  • 相关阅读:
    慎用rm -rf
    Jquery 中a||""的含义
    【学习、总结】Spring security 登陆超时处理
    Eclipse 无限编译Invoking 'Maven Project Builder'导致卡主
    For多重循环 break continue
    随机编码的生成
    QQ互联Oauth2.0认证测试
    Java开发工程师(Web方向)
    Java开发工程师(Web方向)
    前端开发工程师
  • 原文地址:https://www.cnblogs.com/wuhenke/p/1860809.html
Copyright © 2011-2022 走看看