新聞中心
很長(zhǎng)時(shí)間沒親自寫寫東西了,只是收集轉(zhuǎn)載了一些好資料,其實(shí),真正靜下心總結(jié)一下,可以寫的知識(shí)點(diǎn)很多。與困難做斗爭(zhēng),挑戰(zhàn)技術(shù)難關(guān),總會(huì)有些感受心得的。

今天想和網(wǎng)友分享一下“Oracle中BLOB大字段如何讀寫視頻數(shù)據(jù)”,這個(gè)話題起因是我在使用ORACLE備份數(shù)據(jù)時(shí),誤刪了數(shù)據(jù)庫(kù)實(shí)例的控制文件,導(dǎo)致項(xiàng)目數(shù)據(jù)需要重新入庫(kù)。也就是我在彌補(bǔ)這個(gè)錯(cuò)誤時(shí),發(fā)現(xiàn)之前的數(shù)據(jù)入庫(kù)功能,都沒有把200M以上的視頻數(shù)據(jù)導(dǎo)入ORACLE的BLOB字段里,也就是之前的寫入BLOB字段數(shù)據(jù)的方法失效了。這是個(gè)驚人的發(fā)現(xiàn),我發(fā)現(xiàn)因?yàn)檫@個(gè)程序BUG我遺漏掉近300G的視頻數(shù)據(jù),某些單個(gè)視頻文件數(shù)據(jù)量達(dá)到3.6G。
我研究基于ORACLE Text的全文檢索功能,開始接觸ORACLE的BLOB字段,3年多了,自認(rèn)為已經(jīng)熟知BLOB字段的操作。但這次的難題迫使我更深入的認(rèn)識(shí)ORACLE的BLOB字段。
BLOB字段能以二進(jìn)制形式存放4G數(shù)據(jù),200M的視頻數(shù)據(jù)當(dāng)然應(yīng)該沒問(wèn)題,可以出錯(cuò)了?!原來(lái)的方法會(huì)報(bào)“Out of memory”錯(cuò)誤,PLSQL Developer工具導(dǎo)入大視頻數(shù)據(jù),同樣會(huì)報(bào)“Out of memory”錯(cuò)誤。3.6G的視頻數(shù)據(jù)又該如何導(dǎo)入?原來(lái)寫入大字段的方法,導(dǎo)入一般的圖片和文檔一點(diǎn)問(wèn)題沒有。
- ///
- /// 寫大字段內(nèi)容
- /// (新方法,2010.2.4)
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- 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);
- //無(wú)需說(shuō)明類型
- //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];//問(wèn)題1所在
- fsBlob.Read(dataBlob, 0, System.Convert.ToInt32(fsBlob.Length));//問(wèn)題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, "寫數(shù)據(jù)", MessageBoxButtons.OK);
- return false;
- }
- return true;
- }
- ///
- /// 將字符串寫成大字段內(nèi)容
- /// (2010.2.4 修改)
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- 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, "寫數(shù)據(jù)", MessageBoxButtons.OK);
- return false;
- }
- return true;
- }
問(wèn)題1:無(wú)法一次性開辟足夠大空間(如1G),寫入大視頻時(shí),會(huì)導(dǎo)致報(bào)內(nèi)存不足。
問(wèn)題2:System.Convert.ToInt32()會(huì)使3G的視頻時(shí),會(huì)報(bào)類型轉(zhuǎn)換失敗,數(shù)值值過(guò)大。
上面兩個(gè)問(wèn)題在網(wǎng)絡(luò)中所有的方法中都普遍存在的,都會(huì)導(dǎo)致無(wú)法導(dǎo)入700M以上的視頻數(shù)據(jù)。
OLEDB方法對(duì)ORCLE 8以后的大字段操作不在支持,我在解決問(wèn)題的過(guò)程中轉(zhuǎn)向了OracleClient命名空間下的方法來(lái)操作BLOB大字段,主要參考微軟官方http://msdn.microsoft.com/zh-cn/library/cydxhzhz(v=VS.90).aspx和博客園中的http://www.cnblogs.com/zhengmaoch/archive/2005/08/10/212014.html。這兩份資料對(duì)我解決500M以下數(shù)據(jù)量的視頻很有幫助,但是1G甚至是3G以上視頻數(shù)據(jù)是無(wú)法解決的。上面兩處使用了事務(wù)處理在導(dǎo)500M以上數(shù)據(jù)時(shí),會(huì)報(bào)“ORA-22297: warning: Open LOBs exist at transaction commit time ”錯(cuò)誤,主要因?yàn)樘峤皇聞?wù)時(shí)數(shù)據(jù)文件沒有讀完。
經(jīng)過(guò)試驗(yàn)和參考http://msdn.microsoft.com/en-us/library/system.io.filestream.read.aspx方法,終于完全解決上面兩個(gè)問(wèn)題,實(shí)現(xiàn)大視頻量數(shù)據(jù)導(dǎo)入BLOB字段。
- ///
- /// 2010.10.22
- /// 讀取視頻數(shù)據(jù)進(jìn)入ORACLE大字段中
- ///
- ///
- ///
- ///
- 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);//解決問(wèn)題2
- int numBytesRead = 0;
- int n;
- byte[] Buffer = new byte[numBytesToRead];
- //2010.10.25 修改加 將文件分為10塊 防止文件為3.3G以上
- //解決問(wèn)題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("出錯(cuò):"+ex.Message);
- //關(guān)閉
- reader.Close();
- transaction.Commit();
- conn.Close();
- return false;
- }
- }
- reader.Close();
- transaction.Commit();
- conn.Close();
- return true;
- }
上面的方法完全能處理4G以下的視頻數(shù)據(jù)的導(dǎo)入問(wèn)題,已經(jīng)經(jīng)過(guò)驗(yàn)證的。PLSQL Developer工具同樣無(wú)法讀取BLOB字段中的大數(shù)據(jù)量的視頻,如需讀取請(qǐng)?jiān)敿?xì)參照http://www.cnblogs.com/wuhenke/archive/2010/10/25/1860752.html
- ///
- /// 從數(shù)據(jù)庫(kù)中讀出大字段到文件中
- ///
- ///
- ///
- 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數(shù)據(jù)體的何處開始讀取數(shù)據(jù)
- int hopeReadSize = 1024; //希望每次從BLOB數(shù)據(jù)體中讀取數(shù)據(jù)的大小
- long realReadSize = 0;//每次實(shí)際從BLOB數(shù)據(jù)體中讀取數(shù)據(jù)的大小
- //CommandBehavior.SequentialAccess將使OracleDataReader以流的方式加載BLOB數(shù)據(jù)
- 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);
- //循環(huán),每次讀取1024byte大小,并將這些字節(jié)寫入流中
- while ((int)realReadSize == hopeReadSize)
- {
- fs.Write(buffer, 0, hopeReadSize);
- readStartByte += realReadSize;
- realReadSize = dr.GetBytes(0, readStartByte, buffer, 0, hopeReadSize);
- }
- //讀取BLOB數(shù)據(jù)體最后剩余的小于1024byte大小的數(shù)據(jù),并將這些字節(jié)寫入流中
- realReadSize = dr.GetBytes(0, readStartByte, buffer, 0, hopeReadSize);
- fs.Write(buffer, 0, (int)realReadSize);
- }
- //transaction.Commit();
- conn.Close();
- return true;
- }
名稱欄目:Oracle中利用BLOB字段存儲(chǔ)4GB以下視頻數(shù)據(jù)
網(wǎng)址分享:http://fisionsoft.com.cn/article/cohchdo.html


咨詢
建站咨詢
