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 obter uma Microsoft Visual Basic .NET versão deste artigo, consulte 317034
(http://support.microsoft.com/kb/317034/EN-US/
)
.
Para obter uma Microsoft Visual Basic .NET versão deste artigo, consulte 316887
(http://support.microsoft.com/kb/316887/EN-US/
)
.
Este artigo descreve como ler e escrever Binary Large Objects (BLOBs) utilizando métodos GetChunk e AppendChunk com campos de ADO. Também inclui código de exemplo utilizando dados de exemplo NWIND.
Os métodos GetChunk e AppendChunk trabalham com os LongVarChar LongVarWChar e LongVarBinary coluna tipos, também conhecido como TEXT, NTEXT e IMAGE colunas, no Microsoft SQL Server e como campos MEMO e OLE nas bases de dados do Microsoft Jet. Pode identificar estas colunas no ADO testando a propriedade do tipo de um campo de valores adLongVarChar, adLongVarWChar e adLongVarBinary. Também pode testar a propriedade de atributos de um campo para o sinalizador adFldLong:
If fld.Attributes And adFldLong Then
' You can use GetChunk/AppendChunk
mais colunas são frequentemente referidas como BLOBs (Binary objectos grandes) mesmo que podem conter dados de texto. O código de exemplo abaixo fornece dois rotinas, BlobToFile e FileToBlob.
BlobToFile determina o tipo de dados do campo e qual dos três métodos para utilizar para escrever os dados BLOB para um ficheiro no disco. Se os dados BLOB forem suficientemente pequenos, fizer referência ao valor do campo na sua totalidade sem chamar GetChunk. Se o tamanho BLOB for desconhecido, chamará WriteFromUnsizedBinary ou WriteFromUnsizedText para escrever os dados. Este é menos eficiente em termos de fazer cópias adicionais dos dados na memória local do que as rotinas WriteFromBinary e WriteFromText que são utilizados 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 determina se deve utilizar AppendChunk ou atribuir directamente os dados para o campo BLOB com base no tamanho do ficheiro. Uma vez que sempre é possível determinar o tamanho do ficheiro, existem não rotinas "Unsized" porque existem 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
O código de exemplo para BlobToFile e FileToBlob é armazenado no módulo, enquanto o código de teste está por trás o formulário predefinido. O código de teste utiliza cada um dos três métodos para guardar no disco de fotografias (IMAGE/OLE/LongVarBinary) e campos (texto/MEMO/LongVarChar/LongVarWChar)-notas de Andrew Fuller da tabela Empregados da base de dados NWIND. É então lê os ficheiros novamente e cria seis novos registos, leia cada uma das três conjuntos de ficheiros através de dois diferentes métodos de leitura. Nota : a utilizar o ADO 2.1 e posterior, poderá 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 e posterior pode dar a propriedade ActualSize de um campo BLOB de tipo de texto por duas vezes o número de caracteres. Isto é correcto se o campo BLOB contiver texto Unicode, porque o Unicode utiliza 2 bytes por carácter. Esta é incorrecta se o campo BLOB contém texto em ANSI, que utiliza 1 byte por carácter. Se o ActualSize é duas vezes o comprimento de um campo de ANSI, em seguida, GetChunk eventualmente tenta obter depois do fim do campo.
Pode ver este comportamento nos seguintes cenários e pode vê-la em outros cenários:
cenário 1 :
Com um campo de SQL Server 7 NTEXT (texto ANSI), utilizando ambos o OLE DB Provider para SQL Server ou o fornecedor de ODBC com o controlador de ODBC para SQL Server.
Tenha em atenção que a utilizar o SQL Server texto campo (Unicode) funciona com ambos os fornecedores.
cenário 2 :
Com campos de MEMO do Access 97 e com campos de MEMO do Access 2000 com ou sem compressão Unicode, utilizando ambos o OLE DB Provider para Jet 4.0 ou o fornecedor de ODBC com o controlador ODBC Jet 4.0, ODBCJT32.DLL.
Tenha em atenção que, com campos de MEMO do Access 97, ambas as fornecedor OLE DB Jet 3.51 e o fornecedor de ODBC com o trabalho de controladores Jet ODBC 3.51 correctamente.
Existem várias soluções possíveis para Run-time error '94':
Utilizar rs.fieldname.ActualSize \ 2 em vez de rs.fieldname.ActualSize. Este procedimento resolve cada um dos cenários específicos listados acima.
Utilize o método 2 ou 3 abaixo, a propriedade ActualSize nenhum dos quais dependem.
Criar um novo projecto do Visual Basic, no menu Project, seleccione References e seleccione Microsoft ActiveX Data Objects Library ou Microsoft ActiveX Data Objects Library.
Adicione dois CommandButtons (cmdSave e cmdLoad) form(Form1) predefinido.
Adicione o seguinte código. Terá de alterar a cadeia de ligaçã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
Adicionar um novo módulo ao projecto (Módulo1) com o seguinte código:
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
Execute o projecto e clique no botão cmdSave.
No directório C:\, deverá encontrar os seguintes ficheiros: notes1.txt notes2.txt notes3.txt
photo1.dat photo2.dat photo3.dat
Os três ficheiros "Fotografia" devem ter o mesmo tamanho como entre si. Os três ficheiros "notas" devem ter o mesmo tamanho como entre si.
Clique no botão cmdLoad.
Abrir base de dados utilizando acesso e deverá ver seis empregados adicionais com fotografias e notas novamente carregadas correctamente.
Seguem-se algumas sugestões para utilizar BLOBs com o ADO. Estes paralelas muitas das sugestões no seguinte artigo da base de dados de conhecimento da Microsoft:
153238
(http://support.microsoft.com/kb/153238/EN-US/
)
Como utilizar GetChunk e AppendChunk métodos do objecto RDO
É mais eficiente em termos de obtenção de dados BLOB simplesmente armazenar os dados nos ficheiros no servidor com um ponteiro no registo principal (ou pode utilizar algum tipo de directório/ficheiro estruturado sistema baseado no valor de chave primária de nomenclatura). Isto tem a vantagem de (a) eliminando a carga do servidor, (b) permitindo que os ficheiros sejam armazenados num segundo servidor, (c) permitindo rede atributos de segurança a ser definido em ficheiros individuais e (d) permitindo a obtenção de ficheiros mesmo quando o servidor esteja desligado. Isto é especialmente verdade se os ficheiros são algum tipo de tipo de documento, tal como mapas de bits (.bmp), ficheiros de processador (.doc) ou folhas de cálculo (.xls) onde pode apontar a aplicação anfitriã directamente para o ficheiro no servidor.
Quando utilizar alguns fornecedores, nomeadamente ODBC para SQL Server e outras bases de dados, poderá ter de tomar atenção especial em obter dados BLOB, como, por exemplo, colocar BLOB colunas no fim da lista de campos e referência todos os campos não BLOB antes acesso BLOB colunas. Isto dependerá de diversos factores, tais como:
Fornecedor (normalmente ODBC)
Servidor back-end
Localização do cursor (normalmente cliente)
Tipo de cursor
Se estiver a seleccionar VIEW ou obter registos devolvidos a partir de um procedimento armazenado.
Porque depende de vários factores, segue-se uma guia se ocorrerem problemas com BLOB colunas:
Tente um fornecedor de OLE DB nativo em vez de um fornecedor ODBC.
Utilize cursores do lado do servidor (por exemplo, adOpenKeyset).
Seleccione as colunas chave primária em conjunto com outras colunas.
Seleccione as colunas BLOB pela última vez. Seleccione campos individuais, não "*".
Aceder a todas as colunas não BLOB primeiro (armazená-las se necessário).
Acesso BLOB colunas pela ordem especificada. Só poderá referenciar uma vez antes do cursor perde o respectivo valor.
Quando editar uma coluna BLOB utilizando o método AppendChunk, poderá ter de editar, pelo menos, uma coluna BLOB não bem o conjunto de registos. BLOBs normalmente não são actualizáveis com estático ou cursores só de avanço no ODBC datasources.
Se utilizar o ODBC para Jet, não pode actualizar um conjunto de registos devolvido por uma procedimentos armazenados (QueryDef) sequer porque força o controlador para ser só de leitura.
O Microsoft Oracle fornecedor de OLE DB não suporta actualmente aleatório acesso a dados BLOB com cursores do lado do servidor - coluna BLOB tem de aparecer para o fim da cláusula SELECT.
Com a biblioteca de cursores ODBC não é possível utilizar os métodos GetChunk ou AppendChunk num conjunto de registos devolvido por um procedimento armazenado. Isto acontece porque os BLOB não é normalmente obter dados com os restantes dados para poupar largura de banda. Quando um procedimento armazenado cria um conjunto de registos, o controlador de cursor não é possível determinar como consultar os dados BLOB depois do facto porque não é possível determinar as tabelas base ou campos de chave a utilizar. Cursores do lado do servidor minimizar este problema mas limitam a uma única instrução por procedimento armazenado (uma restrição de SQL Server).
O facto de que os utilizadores pretenderem actualizar a respectiva coluna BLOB exige que expõem as respectivas tabelas base e criar o cursor utilizando uma instrução select padrão dessa tabela base. Isto seria VERDADEIRO mesmo se foram codificação directamente para ODBC (não um item de ADO).
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 revisto ou traduzido por humanos. A Microsoft tem artigos traduzidos por aplicações (MT) e artigos traduzidos por tradutores profissionais. O objectivo é simples: oferecer em Português a totalidade dos artigos existentes na base de dados do suporte. Sabemos no entanto que a tradução automática não é sempre perfeita. Esta pode conter erros de vocabulário, sintaxe ou gramática? erros semelhantes aos que um estrangeiro realiza ao falar em Português. A Microsoft não é responsável por incoerências, erros ou estragos realizados na sequência da utilização dos artigos MT por parte dos nossos clientes. A Microsoft realiza actualizações frequentes 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/
)
Qual foi o esforço que despendeu pessoalmente para utilizar este artigo?
Muito baixo
Baixo
Moderado
Elevado
Muito elevado
Diga-nos porquê e o que podemos fazer para melhorar estas informações
Obrigado! Os seus comentários são utilizados para ajudar-nos a melhorar o conteúdo do nosso suporte. Para obter mais opções de assistência, visite a Home Page de Ajuda e Suporte.