ID do artigo: 194975 - Última revisão: segunda-feira, 14 de março de 2005 - Revisão: 3.5

Como de leitura e gravação BLOBs AppendChunk e GetChunk usando

Dica do SistemaEste artigo aplica-se a um sistema operativo diferente do que está a utilizar. Foi desactivado o conteúdo do artigo, que pode não ser relevante para si.
Para uma versão deste artigo do Microsoft Visual Basic. NET, consulte 317034  (http://support.microsoft.com/kb/317034/EN-US/ ) .
Para uma versão deste artigo do Microsoft Visual Basic. NET, consulte 316887  (http://support.microsoft.com/kb/316887/EN-US/ ) .

Nesta página

Expandir tudo | Recolher tudo

Sumário

Este artigo descreve como ler e gravar Binary Large Objects (BLOBs) usando métodos AppendChunk e GetChunk contra campos em ADO. Ele também inclui código de exemplo usando o banco de dados de exemplo NWIND.

Mais Informações

Os métodos AppendChunk e GetChunk trabalham com os tipos de coluna LongVarChar, LongVarWChar e LongVarBinary, também conhecido como TEXT, NTEXT e IMAGE colunas, no Microsoft SQL Server e como campos de MEMO e OLE em bancos de dados Microsoft Jet. Você pode identificar essas colunas no ADO testando a propriedade Type de um campo para os valores adLongVarChar, adLongVarWChar e adLongVarBinary. Você também pode testar a propriedade Attributes de um campo para o sinalizador adFldLong:
If fld.Attributes And adFldLong Then
   ' You can use GetChunk/AppendChunk
				
longo de colunas são normalmente conhecidas como BLOBs (grandes objetos binários) mesmo que eles podem conter dados de texto. O código de exemplo abaixo fornece duas rotinas, BlobToFile e FileToBlob.

BlobToFile

BlobToFile determina o tipo de dados do campo e qual dos três métodos para usar para gravar os dados BLOB em um arquivo de disco. Se os dados BLOB forem pequenos o suficiente ele irá fazer referência o valor do campo em sua totalidade sem chamar GetChunk. Se o tamanho do BLOB for desconhecido, ele irá chamar WriteFromUnsizedBinary ou WriteFromUnsizedText para gravar os dados. Isso é menos eficiente em termos de fazer cópias extras dos dados na memória local que as rotinas de WriteFromBinary e WriteFromText são usadas quando o tamanho dos dados BLOB é conhecido:
    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 determina se deve usar AppendChunk ou atribuir diretamente os dados para o campo BLOB com base no tamanho do arquivo. Como sempre é possível determinar o tamanho do arquivo, não há nenhum rotinas "Unsized" pois há no código de exemplo 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
				

Exemplo

O código de exemplo para BlobToFile e FileToBlob é armazenado em um módulo, enquanto o código de teste está por trás do formulário padrão. O código de teste usa cada um dos três métodos para salvar a foto (IMAGE/OLE/LongVarBinary) de disco e observações (texto/MEMO/LongVarChar/LongVarWChar) campos para Carina Fuller da tabela Funcionários do banco de dados NWIND. -La e lê os arquivos de volta e cria novos seis registros, cada um dos três conjuntos de arquivos por meio de dois diferentes métodos de leitura de leitura. Observação : usando ADO 2.1 ou posterior, você pode ver o seguinte erro na linha de código:
Data = fld.GetChunk(BLOCK_SIZE) :

        Run-time error '94':
        Invalid use of Null
				
ADO 2.1 ou posterior pode relatar a propriedade ActualSize de um campo BLOB de tipo de texto como duas vezes o número de caracteres. Isso é correto se o campo BLOB contiver texto em Unicode, porque Unicode usa 2 bytes por caractere. Isso é incorreto se o campo BLOB contiver texto ANSI, que usa 1 byte por caractere. Se o ActualSize é duas vezes o comprimento de um campo de ANSI, em seguida, GetChunk eventualmente tentará obter após o final do campo.

Você pode ver esse comportamento nas seguintes situações e pode vê-lo em outros cenários:

cenário 1 :

Com um campo do SQL Server 7 NTEXT (texto de ANSI), usar tanto o provedor OLE DB para SQL Server ou o provedor ODBC com o driver ODBC para SQL Server.

Observe que usando o SQL Server texto (Unicode) do campo funciona com os dois provedores.

cenário 2 :

Com campos de MEMO do Access 97 e Access 2000 MEMO campos com ou sem compactação Unicode, usando tanto o provedor OLEDB para o Jet 4.0 ou o provedor ODBC com o driver ODBC Jet 4.0, ODBCJT32.DLL.

Observe que, com campos do Access 97 MEMO, ambos os o OLE DB Provider for Jet 3.51 e o provedor ODBC com o trabalho de driver Jet ODBC 3.51 corretamente.

Existem diversas soluções possíveis para erro de tempo de execução '94':
  • Usar rs.fieldname.ActualSize \ 2 em vez de rs.fieldname.ActualSize. Isso resolve dos cenários específicos listados acima.

  • Use o método 2 ou 3 abaixo, nenhum dos quais dependem da propriedade ActualSize.

Preparando os dados

  1. No Microsoft Access ou outra ferramenta, abra NWIND.MDB.
  2. Abra a tabela Funcionários (ou formulário) e localize "Andrew Pereira."
  3. Cole o conteúdo de um arquivo de texto grande (entre 30000 e 60000 bytes) no campo do Notes.
  4. Salvar as alterações e sair do Access.
  5. Adicione uma fonte de dados ODBC que aponta para o arquivo NWIND.MDB.

Código de exemplo

  1. Criar um novo projeto Visual Basic e a partir do menu Project, selecione References e selecione Microsoft ActiveX Data Objects Library ou Microsoft ActiveX Data Objects Library.
  2. Adicione dois CommandButtons (cmdSave e cmdLoad) form(Form1) padrão.
  3. Adicione o seguinte código. Você precisará alterar a seqüência de conexão fornecida na linha "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. Adicionar um novo módulo ao projeto (Module1) com o código a seguir:
          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. Executar o projeto e clique no botão cmdSave.
  6. No diretório C:\, você deve encontrar os seguintes arquivos: notes1.txt
    notes2.txt
    notes3.txt

    photo1.dat
    photo2.dat
    photo3.dat

    Os três arquivos "foto" devem ser do mesmo tamanho que uns aos outros. Os três arquivos "anotações" devem ser do mesmo tamanho que uns aos outros.

  7. Clique no botão cmdLoad.
  8. Abrir o banco de dados usando acesso e você deve ver seis funcionários adicionais com fotos e anotações volta carregadas corretamente.

Anotações

A seguir está algumas sugestões para usar BLOBs com ADO. Esses paralela muitas das sugestões no seguinte artigo da Base de dados de Conhecimento Microsoft:
153238  (http://support.microsoft.com/kb/153238/EN-US/ ) Como usar métodos AppendChunk do objeto RDO e GetChunk
  1. É mais eficiente em termos de recuperação de dados BLOB para simplesmente armazenar os dados em arquivos no servidor com um ponteiro de registro principal (ou você pode usar algum tipo de diretório/arquivo estruturado nomeação sistema com base no valor da chave primária). Isso tem a vantagem do (a) eliminando a sobrecarga do servidor, (b) permitindo que os arquivos a ser armazenado em um segundo servidor, (c) permitindo rede atributos de segurança a ser definida em arquivos individuais e (d) permitindo recuperação de arquivos, mesmo quando o servidor está desativado. Isso é especialmente verdadeiro se os arquivos estiverem algum tipo de tipo de documento, como bitmaps (.bmp), arquivos de processador (.doc) ou planilhas (.xls) onde você pode apontar o aplicativo host diretamente para o arquivo no servidor.
  2. Ao usar determinados provedores, mais notavelmente ODBC para SQL Server e outros bancos de dados, talvez você precise Tome um cuidado especial em recuperar dados BLOB, como colocar colunas BLOB no final da lista de campos e fazendo referência a todos os campos não-BLOB antes para colunas BLOB de acesso. Isso dependerá de vários fatores, como:
    • Provedor (normalmente ODBC)
    • Servidor back-end
    • Cursor local (normalmente cliente)
    • Tipo de cursor
    • Se você estiver selecionando uma visualização ou obtendo os registros retornados de um procedimento armazenado.
Porque isso depende de diversos fatores, abaixo é um guia se você estiver tendo problemas com colunas BLOB:
  • Tente um provedor OLE DB nativo em vez de um provedor ODBC.
  • Use cursores do lado do servidor (como adOpenKeyset).
  • Selecione as colunas de chave primária com as outras colunas.
  • Selecione as colunas BLOB pela última vez. Selecione campos individuais, não "*".
  • Acessar todas as colunas não-BLOB primeiro (armazená-los se necessário).
  • Colunas BLOB acesso na ordem especificada. Você somente poderá referência a ele vez antes do cursor perde seu valor.
  • Ao editar uma coluna BLOB usando o método AppendChunk, talvez você precise editar pelo menos uma coluna BLOB não no seu conjunto de registros. BLOBs geralmente não são atualizáveis com cursores somente direta no ODBC datasources ou estático.
  • Se você usar ODBC Jet, você não pode atualizar um conjunto de registros retornado por um procedimentos armazenados (QueryDef) em todos os porque o driver obriga a ser somente leitura.
  • O Oracle provedor Microsoft OLE DB não oferece atualmente suporte aleatório acesso a dados BLOB com cursores server-side - coluna BLOB deve aparecer para o final da cláusula SELECT.
Com a biblioteca de cursor ODBC, não é possível usar os métodos AppendChunk ou GetChunk em um conjunto de registros retornado de um procedimento armazenado. Isso ocorre porque os BLOB dados não é normalmente recuperados com o restante dos dados para economizar largura de banda. Quando um procedimento armazenado cria um conjunto de registros, o driver de cursor não pode determinar como consultar os dados BLOB após o fato porque ele não é possível determinar as tabelas base ou campos de chave para usar. Cursores server-side aliviar esse problema, mas limitam você a uma única instrução por procedimento armazenado (uma restrição do SQL Server).

O fato de que os usuários desejam atualizar sua coluna BLOB exige que expõem suas tabelas de base e criar o cursor usando uma instrução select padrão dessa tabela base. Isso seria verdadeiro mesmo se você foram codificando diretamente ao ODBC (não uma coisa ADO).

Referências

Para obter informações adicionais, leia os seguintes artigos na Base de dados de Conhecimento da Microsoft:
185958  (http://support.microsoft.com/kb/185958/EN-US/ ) Como usar o ADO GetChunk/AppendChunk com Oracle para dados BLOB
189415  (http://support.microsoft.com/kb/189415/EN-US/ ) ARQUIVO: AdoChunk.exe usando AppendChunk e GetChunk no Visual C++
Usando objetos de acesso a dados:
103257  (http://support.microsoft.com/kb/103257/EN-US/ ) ACC: Reading, Storing, & Writing Binary Large Objects (BLOBs)

A informação contida neste artigo aplica-se a:
  • 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
Palavras-chave: 
kbmt kbbug kbdatabase kbhowto KB194975 KbMtpt
Tradução automáticaTradução automática
IMPORTANTE: Este artigo foi traduzido por um sistema de tradução automática (também designado por Machine Translation ou MT), não tendo sido portanto traduzido ou revisto por pessoas. A Microsoft possui artigos traduzidos por aplicações (MT) e artigos traduzidos por tradutores profissionais, com o objetivo de oferecer em português a totalidade dos artigos existentes na base de dados de suporte. No entanto, a tradução automática não é sempre perfeita, podendo conter erros de vocabulário, sintaxe ou gramática. A Microsoft não é responsável por incoerências, erros ou prejuízos ocorridos em decorrência da utilização dos artigos MT por parte dos nossos clientes. A Microsoft realiza atualizações freqüentes ao software de tradução automática (MT). Obrigado.
Clique aqui para ver a versão em Inglês deste artigo: 194975  (http://support.microsoft.com/kb/194975/en-us/ )