文章編號: 194975 - 上次校閱: 2005年3月14日 - 版次: 3.5

如何讀取及寫入 BLOB 使用 GetChunk 和 AppendChunk

系統提示本文適用於您使用的作業系統之外的作業系統。與您不相關的文章內容已停用。
本文章的有 Microsoft Visual Basic.NET] 版本請參閱 317034? (http://support.microsoft.com/kb/317034/EN-US/ )
本文章的有 Microsoft Visual Basic.NET] 版本請參閱 316887? (http://support.microsoft.com/kb/316887/EN-US/ )

在此頁中

全部展開 | 全部摺疊

結論

本文將告訴您,如何讀取及寫入二進位大型物件 (BLOB) 使用 GetChunk 和 AppendChunk 方法對在 ADO 中的欄位。它也包括使用 NWIND 範例資料庫的範例程式碼。

其他相關資訊

GetChunk 和 AppendChunk 方法處理 LongVarChar、 LongVarWChar 和 LongVarBinary 欄類型,也稱為 TEXT、 NTEXT,並 IMAGE 資料行在 Microsoft SQL Server] 及 [備忘與 OLE Microsoft Jet 資料庫中的欄位。您可以藉由測試值 adLongVarChar、 adLongVarWChar,和 adLongVarBinary 欄位的 [類型] 屬性來識別在 ADO 中的這些資料行。您也可以測試 adFldLong 旗標欄位的 [屬性] 屬性:
If fld.Attributes And adFldLong Then
   ' You can use GetChunk/AppendChunk
				
Long 資料行通常稱為 BLOB (二進位大型物件) 即使它們可能含有文字資料。下列範例程式碼提供兩種常式 BlobToFile 和 FileToBlob。

BlobToFile

BlobToFile 判斷欄位的資料類型,並使用 BLOB 資料寫入磁碟檔案的三種方法的哪一個。如果 BLOB 資料是夠小,它將不呼叫 GetChunk 參考整個欄位值。如果未知 BLOB 大小,會呼叫 WriteFromUnsizedBinary 或 WriteFromUnsizedText 寫入資料。這是在方面比 WriteFromBinary 和 WriteFromText 常式 BLOB 資料大小已知時所用的本機記憶體中產生之資料的額外複本效率較低:
    BlobToFile                Calls one of the below routines to use GetChunk
    WriteFromBinary         Writes a LongVarBinary of known size to disk
    WriteFromUnsizedBinary  Writes a LongVarBinary on unknown size
    WriteFromText           Writes a LongVarChar of known size
    WriteFromUnsizedText    Writes a LongVarChar of unknown size
				

FileToBlob

FileToBlob 決定是否要使用 AppendChunk 或直接將資料指派給檔案的大小為基礎的 BLOB 欄位。因為檔案的大小可以永遠判定,有沒有 Unsized"常式 BlobToFile 範例程式碼中有:
    FileToBlob          Calls one of the below routines to use AppendChunk
    ReadToBinary      Reads a file into a LongVarBinary column
    ReadToText        Reads a file into a LongVarChar column
				

範例

BlobToFile 和 FileToBlob 範例程式碼會儲存在一個模組中,預設表單後測試程式碼時。測試程式碼使用每三個方法來將儲存到磁碟相片 (IMAGE/OLE/LongVarBinary),並 Andrew Fuller 的注意事項 (TEXT/備忘錄/LongVarChar/LongVarWChar) 欄位,從 NWIND 資料庫的 [員工] 資料表。它然後讀取檔案備份中,並建立六個新的資料錄,讀取這三組透過這兩個不同的檔案的每一個讀取方法。 注意: 使用 ADO 2.1 和更新版本,您可能會看到下列錯誤的程式碼行上:
Data = fld.GetChunk(BLOCK_SIZE) :

        Run-time error '94':
        Invalid use of Null
				
ADO 2.1 和更新版本可能會回報文字類型 BLOB 欄位的 [資料 ActualSize] 屬性為兩倍的字元數。這是正確如果 BLOB 欄位包含 Unicode 文字,因為 Unicode 使用 2 個位元組,每個字元。這是不正確如果 BLOB 欄位包含使用每字元 1 位元組的 ANSI 文字。如果 [ActualSize 兩次 ANSI 欄位的長度然後 GetChunk 最後會嘗試取得超過 [] 欄位的結尾。

您可以查看在下列情況中這種行為,及可能會看到在其他案例中:

案例 1

與 SQL Server 7 NTEXT 欄位 (ANSI 文字),使用 [SQL Server 或 ODBC 提供者與 SQL Server ODBC 驅動程式] 的任一個 OLE DB 提供者。

請注意使用 SQL Server TEXT (Unicode)] 欄位適用於這兩個提供者。

案例 2

與 Access 97 備忘欄位,且具有或沒有 Unicode 壓縮的 Access 2000 備忘欄位,使用任一個 OLE DB 提供者 Jet 4.0 或與 Jet ODBC 4.0 驅動程式 ODBCJT32.DLL ODBC 提供者。

請注意,以 Access 97 備忘欄位兩個 OLE DB 提供者的 Jet 3.51 和 ODBC 提供者與 Jet ODBC 3.51 驅動程式工作正確。

有數種可能的因應措施的執行階段錯誤 '94':
  • 使用 rs.Fieldname.ActualSize \ 代替 rs.Fieldname.ActualSize 2。 這將解析每個以上所列的特定案例。

  • 使用的方法 2 或 3 下面的,都不會依賴 ActualSize 屬性。

正在準備資料

  1. 在 Microsoft Access] 或 [其他] 工具開啟 NWIND.MDB。
  2. 開啟 [員工] 資料表 (或表單),並找出 Andrew Fuller。
  3. 30000 和 60000 位元組) 之間的大型文字檔的內容貼到附註] 欄位。
  4. 儲存所做的變更並結束 Access。
  5. 新增指向 NWIND.MDB 檔案的 ODBC 資料來源。

範例程式碼

  1. 建立新的 Visual Basic 專案,並從 [專案] 功能表選取引用項目,並選取 Microsoft ActiveX 資料物件程式庫或 Microsoft ActiveX 資料物件程式庫。
  2. 將兩個 CommandButtons (cmdSave 和 cmdLoad) 新增到預設 form(Form1)。
  3. 加入下列程式碼。您必須變更提供 cn.Open 」 列上的連接字串:
          Option Explicit
    
          Private Sub CmdSave_Click()
          Dim cn As ADODB.Connection, rs As ADODB.Recordset, SQL As String
            Set cn = New ADODB.Connection
            Set rs = New ADODB.Recordset
            cn.CursorLocation = adUseServer
            cn.Open "dsn=nwind_jet"   ' *** change this ***
            SQL = "SELECT * FROM Employees WHERE LastName='Fuller'"
            rs.Open SQL, cn, adOpenStatic, adLockReadOnly
          '
          ' Save using GetChunk and known size.
          ' FieldSize (ActualSize) > Threshold arg (16384)
          '
            BlobToFile rs!Photo, "c:\photo1.dat", rs!Photo.ActualSize, 16384
            BlobToFile rs!Notes, "c:\notes1.txt", rs!Notes.ActualSize, 16384
             
          ' Uncomment the next line of code, and comment the line above,
          ' to workaround Runtime error '94': Invalid use of Null
          ' BlobToFile rs!Notes, "c:\notes1.txt", rs!Notes.ActualSize \ 2, 16384
    
          '
          ' Save using GetChunk and unknown size.
          ' FieldSize not specified.
          '
            BlobToFile rs!Photo, "c:\photo2.dat"
            BlobToFile rs!Notes, "c:\notes2.txt"
          '
          ' Save without using GetChunk
          ' FieldSize (ActualSize) < Threshold arg (defaults to 1Mb)
          '
            BlobToFile rs!Photo, "c:\photo3.dat", rs!Photo.ActualSize
            BlobToFile rs!Notes, "c:\notes3.txt", rs!Notes.ActualSize
    
          ' Uncomment the next line of code, and comment the line above,
          '   to workaround Runtime error '94': Invalid use of Null
          ' BlobToFile rs!Notes, "c:\notes3.txt", rs!Notes.ActualSize \ 2
    
            rs.Close
            cn.Close
          End Sub
    
          Private Sub CmdLoad_Click()
          Dim cn As ADODB.Connection, rs As ADODB.Recordset, SQL As String
            Set cn = New ADODB.Connection
            Set rs = New ADODB.Recordset
            cn.CursorLocation = adUseServer
            cn.Open "dsn=ole_db_nwind_jet"
            SQL = "SELECT * FROM Employees"
            rs.Open SQL, cn, adOpenKeyset, adLockOptimistic
          '
          ' Load using AppendChunk
          '
            rs.AddNew
            rs!FirstName = "Test"
            rs!LastName = "Fuller11"
            FileToBlob "c:\photo1.dat", rs!Photo, 16384
            FileToBlob "c:\notes1.txt", rs!Notes, 16384
            rs.Update
    
            rs.AddNew
            rs!FirstName = "Test"
            rs!LastName = "Fuller21"
            FileToBlob "c:\photo2.dat", rs!Photo, 16384
            FileToBlob "c:\notes2.txt", rs!Notes, 16384
            rs.Update
    
            rs.AddNew
            rs!FirstName = "Test"
            rs!LastName = "Fuller31"
            FileToBlob "c:\photo3.dat", rs!Photo, 16384
            FileToBlob "c:\notes3.txt", rs!Notes, 16384
            rs.Update
    
          '
          ' Load without using AppendChunk
          '
            rs.AddNew
            rs!FirstName = "Test"
            rs!LastName = "Fuller12"
            FileToBlob "c:\photo1.dat", rs!Photo
            FileToBlob "c:\notes1.txt", rs!Notes
            rs.Update
    
            rs.AddNew
            rs!FirstName = "Test"
            rs!LastName = "Fuller22"
            FileToBlob "c:\photo2.dat", rs!Photo
            FileToBlob "c:\notes2.txt", rs!Notes
            rs.Update
    
            rs.AddNew
            rs!FirstName = "Test"
            rs!LastName = "Fuller32"
            FileToBlob "c:\photo3.dat", rs!Photo
            FileToBlob "c:\notes3.txt", rs!Notes
            rs.Update
    
            rs.Close
            cn.Close
          End Sub
    					
  4. 將新模組加入至專案 (Module1 中),以下列程式碼:
          Option Explicit
    
          Const BLOCK_SIZE = 16384
    
          Sub BlobToFile(fld As ADODB.Field, ByVal FName As String, _
                         Optional FieldSize As Long = -1, _
                         Optional Threshold As Long = 1048576)
          '
          ' Assumes file does not exist
          ' Data cannot exceed approx. 2Gb in size
          '
          Dim F As Long, bData() As Byte, sData As String
            F = FreeFile
            Open FName For Binary As #F
            Select Case fld.Type
              Case adLongVarBinary
                If FieldSize = -1 Then   ' blob field is of unknown size
                  WriteFromUnsizedBinary F, fld
                Else                     ' blob field is of known size
                  If FieldSize > Threshold Then   ' very large actual data
                    WriteFromBinary F, fld, FieldSize
                  Else                            ' smallish actual data
                    bData = fld.Value
                    Put #F, , bData  ' PUT tacks on overhead if use fld.Value
                  End If
                End If
              Case adLongVarChar, adLongVarWChar
                If FieldSize = -1 Then
                  WriteFromUnsizedText F, fld
                Else
                  If FieldSize > Threshold Then
                    WriteFromText F, fld, FieldSize
                  Else
                    sData = fld.Value
                    Put #F, , sData  ' PUT tacks on overhead if use fld.Value
                  End If
                End If
            End Select
            Close #F
          End Sub
    
          Sub WriteFromBinary(ByVal F As Long, fld As ADODB.Field, _
                              ByVal FieldSize As Long)
          Dim Data() As Byte, BytesRead As Long
            Do While FieldSize <> BytesRead
              If FieldSize - BytesRead < BLOCK_SIZE Then
                Data = fld.GetChunk(FieldSize - BLOCK_SIZE)
                BytesRead = FieldSize
              Else
                Data = fld.GetChunk(BLOCK_SIZE)
                BytesRead = BytesRead + BLOCK_SIZE
              End If
              Put #F, , Data
            Loop
          End Sub
    
          Sub WriteFromUnsizedBinary(ByVal F As Long, fld As ADODB.Field)
          Dim Data() As Byte, Temp As Variant
            Do
              Temp = fld.GetChunk(BLOCK_SIZE)
              If IsNull(Temp) Then Exit Do
              Data = Temp
              Put #F, , Data
            Loop While LenB(Temp) = BLOCK_SIZE
          End Sub
    
          Sub WriteFromText(ByVal F As Long, fld As ADODB.Field, _
                            ByVal FieldSize As Long)
          Dim Data As String, CharsRead As Long
            Do While FieldSize <> CharsRead
              If FieldSize - CharsRead < BLOCK_SIZE Then
                Data = fld.GetChunk(FieldSize - BLOCK_SIZE)
                CharsRead = FieldSize
              Else
                Data = fld.GetChunk(BLOCK_SIZE)
                CharsRead = CharsRead + BLOCK_SIZE
              End If
              Put #F, , Data
            Loop
          End Sub
    
          Sub WriteFromUnsizedText(ByVal F As Long, fld As ADODB.Field)
          Dim Data As String, Temp As Variant
            Do
              Temp = fld.GetChunk(BLOCK_SIZE)
              If IsNull(Temp) Then Exit Do
              Data = Temp
              Put #F, , Data
            Loop While Len(Temp) = BLOCK_SIZE
          End Sub
    
          Sub FileToBlob(ByVal FName As String, fld As ADODB.Field, _
                         Optional Threshold As Long = 1048576)
          '
          ' Assumes file exists
          ' Assumes calling routine does the UPDATE
          ' File cannot exceed approx. 2Gb in size
          '
          Dim F As Long, Data() As Byte, FileSize As Long
            F = FreeFile
            Open FName For Binary As #F
            FileSize = LOF(F)
            Select Case fld.Type
              Case adLongVarBinary
                If FileSize > Threshold Then
                  ReadToBinary F, fld, FileSize
                Else
                  Data = InputB(FileSize, F)
                  fld.Value = Data
                End If
              Case adLongVarChar, adLongVarWChar
                If FileSize > Threshold Then
                  ReadToText F, fld, FileSize
                Else
                  fld.Value = Input(FileSize, F)
                End If
            End Select
            Close #F
          End Sub
    
          Sub ReadToBinary(ByVal F As Long, fld As ADODB.Field, _
                           ByVal FileSize As Long)
          Dim Data() As Byte, BytesRead As Long
            Do While FileSize <> BytesRead
              If FileSize - BytesRead < BLOCK_SIZE Then
                Data = InputB(FileSize - BytesRead, F)
                BytesRead = FileSize
              Else
                Data = InputB(BLOCK_SIZE, F)
                BytesRead = BytesRead + BLOCK_SIZE
              End If
              fld.AppendChunk Data
            Loop
          End Sub
    
          Sub ReadToText(ByVal F As Long, fld As ADODB.Field, _
                         ByVal FileSize As Long)
          Dim Data As String, CharsRead As Long
            Do While FileSize <> CharsRead
              If FileSize - CharsRead < BLOCK_SIZE Then
                Data = Input(FileSize - CharsRead, F)
                CharsRead = FileSize
              Else
                Data = Input(BLOCK_SIZE, F)
                CharsRead = CharsRead + BLOCK_SIZE
              End If
              fld.AppendChunk Data
            Loop
          End Sub
    					
  5. 執行專案,然後按一下 cmdSave 按鈕。
  6. 您應該在 C:\] 目錄中找到下列檔案: notes1.txt
    notes2.txt
    notes3.txt

    photo1.dat
    photo2.dat
    photo3.dat

    三個 「 相片 」 檔案應該是相同彼此的大小。三個 「 備忘稿 」 檔案應該是相同彼此的大小。

  7. 按一下 [cmdLoad] 按鈕。
  8. 開啟資料庫使用 Access,而且您應該會看到相片和載入回正確的備忘稿的六個其他員工。

備忘稿

以下是一些建議,搭配 ADO 使用 BLOB。這些平行許多建議下列 「 Microsoft 知識庫 」 文件中:
153238? (http://support.microsoft.com/kb/153238/EN-US/ ) 如何使用 GetChunk 和 AppendChunk RDO 物件的方法
  1. 它是較有效率的方式方面的只是將資料儲存在主要資料錄的指標具有伺服器上的檔案中的 BLOB 資料擷取 (或您可以使用某種結構化目錄/檔案命名系統根據主索引鍵的值)。這也有 (a) 消除伺服器的額外負荷、 (b) 允許將檔案儲存在第二個伺服器上、 (c) 允許網路在個別檔案上設定安全性屬性以及 (d) 允許檔案擷取甚至當伺服器向下時的好處。是特別如此,如果檔案是某種文件型別例如點陣圖 (.bmp)]、 [文書處理器檔案 (.doc)] 或 [試算表 (.xls) 您可以在此指主應用程式,直接到伺服器上檔案。
  2. 使用特定提供者,最值得注意的是 ODBC SQL Server 和其他資料庫時您可能必須特別注意擷取 BLOB 資料、 例如欄位清單結尾處放置 BLOB 資料行和參考來存取 BLOB 資料行之前的所有非 BLOB 欄位中。這將例如視許多因素:
    • 提供者 (通常 ODBC)
    • 後端伺服器
    • 游標位置 (通常是用戶端)
    • 資料指標類型
    • 您是否正在從一個檢視中選取,或者取得從預存程序傳回的資料錄。
因為許多因素而定下, 面是輔助線如果您有 BLOB 資料行的問題:
  • 請試著原生的 OLE DB 提供者,而非 ODBC 提供者。
  • 使用伺服器端資料指標 (例如 adOpenKeyset)。
  • 選取主索引鍵資料行中,除了任何其他資料行。
  • 最後一次選取 BLOB 資料行。無法選取個別欄位"*"。
  • 第一次存取所有的非 BLOB 資料行 (儲存它們如有必要)。
  • 存取 BLOB 資料行指定的順序。您只可以一次參考它,游標將會遺失其值之前。
  • 在編輯 BLOB 資料行使用 AppendChunk 方法時您可能必須編輯您資料錄集中至少一個非 BLOB 資料行。Blob 通常不是可更新與靜態或僅轉寄的資料指標在 ODBC 資料來源上。
  • 如果您使用 [ODBC Jet 無法更新資料錄集傳回的預存程序 (QueryDef) 根本因為驅動程式會強制他們成為唯讀。
  • Microsoft Oracle OLE DB 提供者目前不支援 BLOB 資料與伺服器端資料指標-隨機存取 BLOB 資料行必須出現 SELECT 子句的結尾。
與 ODBC 資料指標程式庫不可能在預存程序傳回資料錄集上使用 GetChunk 或 AppendChunk 方法。這是因為 BLOB 資料不正常擷取與其餘的資料以節省頻寬。當預存程序會建立一個資料錄集時,游標驅動程式無法判斷如何因為它無法判斷基底資料表或索引鍵欄位使用事實之後查詢的 BLOB 資料。伺服器端資料指標減輕這個問題,但您限制到每個預存程序 (SQL Server 限制) 的單一陳述式。

使用者想要更新其 BLOB 資料行的事實會要求他們公開 (Expose) 其基底資料表,並使用標準的選取陳述式從該基底資料表來建立資料指標。即使您已撰寫程式碼直接到 ODBC (不 ADO 事項),這也將成為則為 True。

?考

如需詳細資訊請參閱下列文件 「 Microsoft 知識庫 」 中:
185958? (http://support.microsoft.com/kb/185958/EN-US/ ) 如何使用 ADO GetChunk AppendChunk 與 Oracle BLOB 資料
189415? (http://support.microsoft.com/kb/189415/EN-US/ ) 在 Visual C++ 中使用 GetChunk 和 AppendChunk FILE: AdoChunk.exe
使用資料存取物件:
103257? (http://support.microsoft.com/kb/103257/EN-US/ ) ACC: 讀取儲存,寫入二進位大型物件 (BLOB) (& I)

這篇文章中的資訊適用於:
  • Microsoft ActiveX Data Objects 1.5
  • Microsoft ActiveX Data Objects 2.0
  • Microsoft ActiveX Data Objects 2.1 Service Pack 2
  • Microsoft ActiveX Data Objects 2.5
  • Microsoft ActiveX Data Objects 2.6
  • Microsoft ActiveX Data Objects 2.7
  • Microsoft Visual Basic 6.0 Professional Edition
  • Microsoft Visual Basic Enterprise Edition for Windows 6.0
關鍵字:?
kbmt kbbug kbdatabase kbhowto KB194975 KbMtzh
機器翻譯機器翻譯
重要:本文是以 Microsoft 機器翻譯軟體翻譯而成,而非使用人工翻譯而成。Microsoft 同時提供使用者人工翻譯及機器翻譯兩個版本的文章,讓使用者可以依其使用語言使用知識庫中的所有文章。但是,機器翻譯的文章可能不盡完美。這些文章中也可能出現拼字、語意或文法上的錯誤,就像外國人在使用本國語言時可能發生的錯誤。Microsoft 不為內容的翻譯錯誤或客戶對該內容的使用所產生的任何錯誤或損害負責。Microsoft也同時將不斷地就機器翻譯軟體進行更新。
按一下這裡查看此文章的英文版本:194975? (http://support.microsoft.com/kb/194975/en-us/ )
Microsoft及(或)其供應商不就任何在本伺服器上發表的文字資料及其相關圖表資訊的恰當性作任何承諾。所有文字資料及其相關圖表均以「現狀」供應,不負任何擔保責任。Microsoft及(或)其供應商謹此聲明,不負任何對與此資訊有關之擔保責任,包括關於適售性、適用於某一特定用途、權利或不侵權的明示或默示擔保責任。Microsoft及(或)其供應商無論如何不對因或與使用本伺服器上資訊或與資訊的實行有關而引起的契約、過失或其他侵權行為之訴訟中的特別的、間接的、衍生性的損害或任何因使用而喪失所導致的之損害、資料或利潤負任何責任。