C#修改DataReader默認行為
學習C#時,經(jīng)常會遇到C#修改DataReader默認行為問題,這里將介紹C#修改DataReader默認行為問題的解決方法。
DataReader默認行為是在整個數(shù)據(jù)行可用時立即以行的形式加載傳入數(shù)據(jù)。但是,對于二進制大對象 (BLOB) 則需要進行不同的處理,因為它們可能包含數(shù)十億字節(jié)的數(shù)據(jù),而單個行中無法包含如此多的數(shù)據(jù)。Command.ExecuteReader 方法具有一個重載,它將采用 CommandBehavior 參數(shù)來用C#修改DataReader默認行為。您可以將 CommandBehavior.SequentialAccess 傳遞到 ExecuteReader 方法來用C#修改DataReader默認行為,以便讓 DataReader 按照順序在接收到數(shù)據(jù)時立即將其加載,而不是加載數(shù)據(jù)行。這是加載 BLOB 或其他大數(shù)據(jù)結構的理想方案。
在將 DataReader 設置為使用 SequentialAccess 時,務必要注意訪問所返回字段的順序。DataReader 的默認行為是在整個行可用時立即加載該行,這使您能夠在讀取下一行之前按任何順序訪問所返回的字段。但是,當使用 SequentialAccess 時,必須按順序訪問由 DataReader 返回的不同字段。例如,如果查詢返回三個列,其中第三列是 BLOB,則必須在訪問第三個字段中的 BLOB 數(shù)據(jù)之前返回第一個和第二個字段的值。如果在訪問第一個或第二個字段之前訪問第三個字段,則第一個和第二個字段值將不再可用。這是因為 SequentialAccess 已修改 DataReader,使其按順序返回數(shù)據(jù),當 DataReader 已經(jīng)讀取超過特定數(shù)據(jù)時,該數(shù)據(jù)將不可用。
當訪問 BLOB 字段中的數(shù)據(jù)時,請使用 DataReader 的 GetBytes 類型化訪問器,該訪問器將使用二進制數(shù)據(jù)填充 byte 數(shù)組。您可以指定要返回的特定數(shù)據(jù)緩沖區(qū)大小以及從返回的數(shù)據(jù)中讀取的第一個字節(jié)的起始位置。GetBytes 將返回 long 值,它表示所返回的字節(jié)數(shù)。如果向 GetBytes 傳遞空的 byte 數(shù)組,所返回的長值將是 BLOB 中字節(jié)的總數(shù)。您可以選擇將字節(jié)數(shù)組中的某索引指定為所讀取數(shù)據(jù)的起始位置。
以下示例從 Microsoft SQL Server 中的 pubs 示例數(shù)據(jù)庫中返回發(fā)行者 ID 和徽標。發(fā)行者 ID (pub_id) 是字符字段,而徽標則是圖形,即 BLOB。請注意,由于必須按順序訪問字段,所以將在訪問徽標之前訪問當前數(shù)據(jù)行的發(fā)行者 ID。
C#修改DataReader默認行為的代碼:
- Dim pubsConn As SqlConnection = New SqlConnection
(Data Source=localhost;Integrated Security=SSPI;Initial Catalog=pubs;)- Dim logoCMD As SqlCommand = New SqlCommand
(SELECT pub_id, logo FROM pub_info, pubsConn)- Dim fs As FileStream ' Writes the BLOB to a file (*.bmp).
- Dim bw As BinaryWriter ' Streams the binary data to the FileStream object.
- Dim bufferSize As Integer = 100 ' The size of the BLOB buffer.
- Dim outbyte(bufferSize - 1) As Byte ' The BLOB byte()
buffer to be filled by GetBytes.- Dim retval As Long ' The bytes returned from GetBytes.
- Dim startIndex As Long = 0 ' The starting position in the BLOB output.
- Dim pub_id As String = ' The publisher id to use in the file name.
- ' Open the connection and read data into the DataReader.
- pubsConn.Open()
- Dim myReader As SqlDataReader = logoCMD.ExecuteReader
(CommandBehavior.SequentialAccess)- Do While myReader.Read()
- ' Get the publisher id, which must occur before getting the logo.
- pub_id = myReader.GetString(0)
- ' Create a file to hold the output.
- fs = New FileStream(logo & pub_id & .bmp, FileMode.OpenOrCreate, FileAccess.Write)
- bw = New BinaryWriter(fs)
- ' Reset the starting byte for a new BLOB.
- startIndex = 0
- ' Read bytes into outbyte() and retain the number of bytes returned.
- retval = myReader.GetBytes(1, startIndex, outbyte, 0, bufferSize)
- ' Continue reading and writing while there are bytes beyond the size of the buffer.
- Do While retval = bufferSize
- bw.Write(outbyte)
- bw.Flush()
- ' Reposition the start index to the end of the last buffer and fill the buffer.
- startIndexstartIndex = startIndex + bufferSize
- retval = myReader.GetBytes(1, startIndex, outbyte, 0, bufferSize)
- Loop
- ' Write the remaining buffer.
- bw.Write(outbyte)
- bw.Flush()
- ' Close the output file.
- bw.Close()
- fs.Close()
- Loop
- ' Close the reader and the connection.
- myReader.Close()
- pubsConn.Close()
- [C#]
- SqlConnection pubsConn = new SqlConnection
(Data Source=localhost;Integrated Security=SSPI;Initial Catalog=pubs;);- SqlCommand logoCMD = new SqlCommand(SELECT pub_id, logo FROM pub_info, pubsConn);
- FileStream fs;
- // Writes the BLOB to a file (*.bmp).
- BinaryWriter bw;
- // Streams the BLOB to the FileStream object.
- int bufferSize = 100;
- // Size of the BLOB buffer.
- byte[] outbyte = new byte[bufferSize];
- // The BLOB byte[] buffer to be filled by GetBytes.
- long retval; // The bytes returned from GetBytes.
- long startIndex = 0;
- // The starting position in the BLOB output.
- string pub_id = ;
- // The publisher id to use in the file name.
- // Open the connection and read data into the DataReader.
- pubsConn.Open();
- SqlDataReader myReader = logoCMD.ExecuteReader(CommandBehavior.SequentialAccess);
- while (myReader.Read())
- {
- // Get the publisher id, which must occur before getting the logo.
- pub_id = myReader.GetString(0);
- // Create a file to hold the output.
- fs = new FileStream(logo + pub_id + .bmp, FileMode.OpenOrCreate, FileAccess.Write);
- bw = new BinaryWriter(fs);
- // Reset the starting byte for the new BLOB.
- startIndex = 0;
- // Read the bytes into outbyte[] and retain the number of bytes returned.
- retval = myReader.GetBytes(1, startIndex, outbyte, 0, bufferSize);
- // Continue reading and writing while there are bytes beyond the size of the buffer.
- while (retval == bufferSize)
- {
- bw.Write(outbyte);
- bw.Flush();
- // Reposition the start index to the end of the last buffer and fill the buffer.
- startIndex+= bufferSize;
- retval = myReader.GetBytes(1, startIndex, outbyte, 0, bufferSize);
- }
- // Write the remaining buffer.
- bw.Write(outbyte);
- bw.Flush();
- // Close the output file.
- bw.Close();
- fs.Close();
- }
- // Close the reader and the connection.
- myReader.Close();
- pubsConn.Close();
【編輯推薦】