GRAVAR DADOS VARBINARY(MAX) GRANDES
Amigos bom dia.
No SQL Server 2008 R2 Express, eu criei 2 bancos, um principal com todas as tabelas e um View para consultar e inserir dados na única tabela do banco 2, usado só para arquivos binários (em função da capacidade do express).
Tudo funciona perfeitamente, porém para arquivos bem pequenos, pois ao tentar incluir um arquivo de apenas 256kb deu erro 8152 (dados truncados) e não gravou.
O limite do campo Varbinary(Max) é de 2 GB, porém ao tentar passar o arquivo como parâmetro SQL, surge a mensagem que o limite máximo é 8 mil bytes apenas.
Como resolver isso, já que o SQL aceita 2 GB por campo, mas não se pode passar uma arquivo com mais de 256 kb ?
testei select @@TEXTSIZE e retornou o tamanho de 2147483647 (que é o limite de 2GB), então porque não grava?
O código que uso para passar o arquivo em array de bytes é:
O erro surge na linha em vermelho que deveria receber qualquer arquivo.
ALGUéM saberia como resolver isso?????
No SQL Server 2008 R2 Express, eu criei 2 bancos, um principal com todas as tabelas e um View para consultar e inserir dados na única tabela do banco 2, usado só para arquivos binários (em função da capacidade do express).
Tudo funciona perfeitamente, porém para arquivos bem pequenos, pois ao tentar incluir um arquivo de apenas 256kb deu erro 8152 (dados truncados) e não gravou.
O limite do campo Varbinary(Max) é de 2 GB, porém ao tentar passar o arquivo como parâmetro SQL, surge a mensagem que o limite máximo é 8 mil bytes apenas.
Como resolver isso, já que o SQL aceita 2 GB por campo, mas não se pode passar uma arquivo com mais de 256 kb ?
testei select @@TEXTSIZE e retornou o tamanho de 2147483647 (que é o limite de 2GB), então porque não grava?
O código que uso para passar o arquivo em array de bytes é:
....
[txt-color=#e80000]cmd.Parameters.Add([Ô]@ARQUIVOBINARIO[Ô], SqlDbType.VarBinary);[/txt-color]
cmd.Parameters[[Ô]@ARQUIVOBINARIO[Ô]].Value = myArquivoBinario.ARQUIVOBINARIO;
//grava novo documento digital no banco
myIDNovoArquivo = (Int32)cmd.ExecuteScalar(); // recebe o novo ID do
O erro surge na linha em vermelho que deveria receber qualquer arquivo.
ALGUéM saberia como resolver isso?????
Luis,
Faz um teste, em vez de você utilizar o datatype [Ô]SqlDbType.VarBinary[Ô] use o [Ô]SqlDbType.SqlFileStream[Ô]. Não lembro se é SqlDbType ou só SqlTypes.
Veja se resolve o problema.
Faz um teste, em vez de você utilizar o datatype [Ô]SqlDbType.VarBinary[Ô] use o [Ô]SqlDbType.SqlFileStream[Ô]. Não lembro se é SqlDbType ou só SqlTypes.
Veja se resolve o problema.
Rodrigo eu tentei, mas não existe SqlFileStream dentro de SqlDbType e também não existe SqlTypes.
Será que existe isso? Tem que incluir algum using ?
Tentei trocar o campo de Varbinary(Max) para Image e até setando o tamanho máximo, mas deu o mesmo erro.
cmd.Parameters.Add([Ô]@ARQUIVOBINARIO[Ô], SqlDbType.Image, 2147483647);
Acho que o problema está no cmd da conexão ao passar o parâmetro ao SQL, parece que o parâmetro é que limita o tamanho do dado a ser enviado ao banco, independente do limite que o campo aceite.
No código C#, eu fiz o Stream para ler o arquivo do Disco, para reduzir o tamanho e não sobrecarregar o banco eu ZIPO ele primeiro e só depois passo o array de bytes para o SQL, mas não funciona mesmo, só com arquivos inferiores a 8 Kb.
Não uso o stream do próprio SQL Server, pois para isso teria de mudar totalmente o código atual. Além disso tem de configurar o SQL Server para aceitar o Stream que não é ativado por padrão. Nem sei direito todos os passos que seriam necessários para isso e se a versão Express funciona normalmente.
Será que existe isso? Tem que incluir algum using ?
Tentei trocar o campo de Varbinary(Max) para Image e até setando o tamanho máximo, mas deu o mesmo erro.
cmd.Parameters.Add([Ô]@ARQUIVOBINARIO[Ô], SqlDbType.Image, 2147483647);
Acho que o problema está no cmd da conexão ao passar o parâmetro ao SQL, parece que o parâmetro é que limita o tamanho do dado a ser enviado ao banco, independente do limite que o campo aceite.
No código C#, eu fiz o Stream para ler o arquivo do Disco, para reduzir o tamanho e não sobrecarregar o banco eu ZIPO ele primeiro e só depois passo o array de bytes para o SQL, mas não funciona mesmo, só com arquivos inferiores a 8 Kb.
Não uso o stream do próprio SQL Server, pois para isso teria de mudar totalmente o código atual. Além disso tem de configurar o SQL Server para aceitar o Stream que não é ativado por padrão. Nem sei direito todos os passos que seriam necessários para isso e se a versão Express funciona normalmente.
Tenta assim.
cmd.Parameters.Add([Ô]@imagem[Ô], arquivoBinario.Length).Value = arquivoBinario;
cmd.Parameters.Add([Ô]@imagem[Ô], arquivoBinario.Length).Value = arquivoBinario;
Guimoraes vamos lá...
Sua instrução funcionou só depois que alterei para:
cmd.Parameters.AddWithValue([Ô]@imagem[Ô], arquivoBinario.Length).Value = arquivoBinario;
Pois a sintaxe sugerida com Add é obsoleta na versão 2008 do SQL.
Porém após gravar os dados, ao recuperá-los no meu aplicativo, não consigo mais abrir o arquivo gravado, pois parece que o formato usado na gravação ficou diferente do ArraysByte que era enviado inicialmente. O que ocorreu com os dados no meu arquivoBinario ao ser gravado no banco?
Como posso recuperá-los corretamente?
Sua instrução funcionou só depois que alterei para:
cmd.Parameters.AddWithValue([Ô]@imagem[Ô], arquivoBinario.Length).Value = arquivoBinario;
Pois a sintaxe sugerida com Add é obsoleta na versão 2008 do SQL.
Porém após gravar os dados, ao recuperá-los no meu aplicativo, não consigo mais abrir o arquivo gravado, pois parece que o formato usado na gravação ficou diferente do ArraysByte que era enviado inicialmente. O que ocorreu com os dados no meu arquivoBinario ao ser gravado no banco?
Como posso recuperá-los corretamente?
Luis,
Tenta também com o [Ô]Text[Ô]
Tenta também com o [Ô]Text[Ô]
Rodrigo não entendi, que Text é esse? Estou passando uma matriz de Bytes[]
Guimoraes, Agora funcionou (VIVA!!!!!!). Eu cometi um erro, nos testes que estava fazendo para corrigir, e só agora reparei. Funcionou direitinho.
Muito obrigado amigo.
Guimoraes, Agora funcionou (VIVA!!!!!!). Eu cometi um erro, nos testes que estava fazendo para corrigir, e só agora reparei. Funcionou direitinho.
Muito obrigado amigo.
Segue EXEMPLO de como salvar anexos, acho que com isso vc consegue agora:
Obs.: Para o comando funcionar, o arquivo a ser transferido para o SQL, tem que estar em um servidor que o SQL reconheça, isso é muito importante.
VB.NET
No form de Salvar o Anexo:
Função para Salvar o anexo:
Public Function sp_Anexo(ByVal pstrOpcao As String, ByVal clsAnex As clsAnexo) As String
Dim sb As New System.Text.StringBuilder
Select Case pstrOpcao
Case [Ô]SALVAR[Ô]
sb.Append([Ô]INSERT INTO HelpDesk_Imagem (ID_Chamado, Descricao, Arquivo)[Ô])
sb.Append([Ô] SELECT [Ô])
sb.Append(clsAnex.pID_Chamado & [Ô] AS ID_Chamado[Ô])
sb.Append([Ô],[ô][Ô] & clsAnex.pDescricao & [Ô][ô] AS Descricao[Ô])
[ô]sb.Append([Ô], * FROM OPENROWSET (BULK [ô]\\data3\Arquivos \HelpDesk\Imagem_Temp\MVREGCLEAN.txt[ô], SINGLE_BLOB) AS Arquivo[Ô])
sb.Append([Ô], * FROM OPENROWSET (BULK [ô][Ô] & clsAnex.pAnexo & [Ô][ô], SINGLE_BLOB) AS Arquivo[Ô])
Case [Ô]GRIDANEXOS[Ô]
sb.Append([Ô]SELECT[Ô])
sb.Append([Ô] *[Ô])
sb.Append([Ô] FROM[Ô])
sb.Append([Ô] HelpDesk_Imagem[Ô])
sb.Append([Ô] WHERE[Ô])
sb.Append([Ô] ID_Chamado = [Ô] & clsAnex.pID_Chamado)
Case [Ô]BAIXARANEXO[Ô]
sb.Append([Ô]SELECT[Ô])
sb.Append([Ô] Descricao[Ô])
sb.Append([Ô] ,Arquivo[Ô])
sb.Append([Ô] FROM[Ô])
sb.Append([Ô] HelpDesk_Imagem[Ô])
sb.Append([Ô] WHERE[Ô])
sb.Append([Ô] ID_Imagem = [Ô] & clsAnex.pID_Imagem)
End Select
Return sb.ToString()
End Function
Função para baixar e Salvar o anexo em um diretório:
Obs.: Para o comando funcionar, o arquivo a ser transferido para o SQL, tem que estar em um servidor que o SQL reconheça, isso é muito importante.
VB.NET
No form de Salvar o Anexo:
Private Sub cmdAnexo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdAnexo.Click
Dim dr As DialogResult = Me.ofdAnexo.ShowDialog()
[ô]Define as propriedades do controle OpenFileDialog
Me.ofdAnexo.Multiselect = False
Me.ofdAnexo.Title = [Ô]Selecionar Anexos[Ô]
ofdAnexo.InitialDirectory = [Ô]C:\[Ô]
ofdAnexo.Filter = [Ô]Todos os Arquivos (*.*)|*.*[Ô]
ofdAnexo.CheckFileExists = True
ofdAnexo.CheckPathExists = True
ofdAnexo.FilterIndex = 2
ofdAnexo.RestoreDirectory = True
ofdAnexo.ReadOnlyChecked = True
ofdAnexo.ShowReadOnly = True
If dr = System.Windows.Forms.DialogResult.OK Then
[ô]*** Le os arquivos selecionados caso a propriedade Multselect seja True
[ô]For Each file As [String] In ofdAnexo.FileNames
[ô] txtArquivo.Text += file
[ô] txtArquivo.Tag += ofdAnexo.SafeFileName
[ô]Next
txtArquivo.Text = ofdAnexo.FileName
txtArquivo.Tag = ofdAnexo.SafeFileName
End If
End Sub
Função para Salvar o anexo:
Public Function sp_Anexo(ByVal pstrOpcao As String, ByVal clsAnex As clsAnexo) As String
Dim sb As New System.Text.StringBuilder
Select Case pstrOpcao
Case [Ô]SALVAR[Ô]
sb.Append([Ô]INSERT INTO HelpDesk_Imagem (ID_Chamado, Descricao, Arquivo)[Ô])
sb.Append([Ô] SELECT [Ô])
sb.Append(clsAnex.pID_Chamado & [Ô] AS ID_Chamado[Ô])
sb.Append([Ô],[ô][Ô] & clsAnex.pDescricao & [Ô][ô] AS Descricao[Ô])
[ô]sb.Append([Ô], * FROM OPENROWSET (BULK [ô]\\data3\Arquivos \HelpDesk\Imagem_Temp\MVREGCLEAN.txt[ô], SINGLE_BLOB) AS Arquivo[Ô])
sb.Append([Ô], * FROM OPENROWSET (BULK [ô][Ô] & clsAnex.pAnexo & [Ô][ô], SINGLE_BLOB) AS Arquivo[Ô])
Case [Ô]GRIDANEXOS[Ô]
sb.Append([Ô]SELECT[Ô])
sb.Append([Ô] *[Ô])
sb.Append([Ô] FROM[Ô])
sb.Append([Ô] HelpDesk_Imagem[Ô])
sb.Append([Ô] WHERE[Ô])
sb.Append([Ô] ID_Chamado = [Ô] & clsAnex.pID_Chamado)
Case [Ô]BAIXARANEXO[Ô]
sb.Append([Ô]SELECT[Ô])
sb.Append([Ô] Descricao[Ô])
sb.Append([Ô] ,Arquivo[Ô])
sb.Append([Ô] FROM[Ô])
sb.Append([Ô] HelpDesk_Imagem[Ô])
sb.Append([Ô] WHERE[Ô])
sb.Append([Ô] ID_Imagem = [Ô] & clsAnex.pID_Imagem)
End Select
Return sb.ToString()
End Function
Função para baixar e Salvar o anexo em um diretório:
Private Sub sSalvaArquivo()
Dim strQuery As String
Dim strNome As String
Dim ds As New DataSet
ds.Dispose()
Try
objConexaoImagens.AbreConexao()
For Each grdAnex As DataGridViewRow In grdAnexos.Rows
If grdAnex.Cells(edgvSupervisor.CheckBox).Value = True Then
objclsAnexo.pID_Imagem = grdAnex.Cells(edgvAnexos.ID_Imagem).Value
strQuery = objclsAnexo.fPesquisa([Ô]BAIXARANEXO[Ô])
ds = New DataSet([Ô]Anexos[Ô])
ds.Dispose()
ds = objConexaoImagens.AbreDataSet(strQuery, [Ô]Anexos[Ô])
Dim MyData() As Byte = New Byte(0) {}
Dim myRow As DataRow = ds.Tables([Ô]Anexos[Ô]).Rows(0)
strNome = myRow([Ô]Descricao[Ô]).ToString
MyData = CType(myRow([Ô]Arquivo[Ô]), Byte())
Using stream = New FileStream(txtCaminho.Text & [Ô]\[Ô] & strNome, FileMode.Create, FileAccess.Write)
stream.Write(MyData, 0, Convert.ToInt32(MyData.Length))
End Using
End If
Next grdAnex
Call frmMsgBox.Show([Ô]Arquivo(s) salvo(s) com sucesso.[Ô], MsgBoxStyle.Information, Me.Text)
Catch ex As Exception
MsgBox(ex.Message)
Finally
objConexaoImagens.FechaConexao()
End Try
End Sub
Guimoraes, desculpe reabrir o post, mas após fazer alguns testes o problema voltou a ocorrer, esquisito isso.
Fiz o teste com o arquivo 256kb, gravou, fiz com um arquivo 2 MB, gravou, fiz com um arquivos 6 MB gravou, mas ao tentar um de 7,5 MB deu o mesmo erro.
Que coisa [Ô]Doida[Ô], alguma idéia?
Rodrigo obrigado pelo código, só que uso C#. Já tenho toda a rotina pronta, eu leio o arquivo do disco em FileStream, depois compacto ele ZIp e por último passo o array byte[] desse ZIP para gravar no banco, o processo depois é inverso. Mas não entendo o porque limitar o tamanho do arquivo enviado. Agora está em mais de 7,5 MB. Eu até vou fazer uma rotina para testar o tamanho do arquivo e avisar ao usuário, estou até pensando em restringir esse tamanho a 1 MB, mas não vejo lógica nessa limitação ou problema da gravação, por isso quero resolver.
Obrigado
Fiz o teste com o arquivo 256kb, gravou, fiz com um arquivo 2 MB, gravou, fiz com um arquivos 6 MB gravou, mas ao tentar um de 7,5 MB deu o mesmo erro.
Que coisa [Ô]Doida[Ô], alguma idéia?
Rodrigo obrigado pelo código, só que uso C#. Já tenho toda a rotina pronta, eu leio o arquivo do disco em FileStream, depois compacto ele ZIp e por último passo o array byte[] desse ZIP para gravar no banco, o processo depois é inverso. Mas não entendo o porque limitar o tamanho do arquivo enviado. Agora está em mais de 7,5 MB. Eu até vou fazer uma rotina para testar o tamanho do arquivo e avisar ao usuário, estou até pensando em restringir esse tamanho a 1 MB, mas não vejo lógica nessa limitação ou problema da gravação, por isso quero resolver.
Obrigado
Luiz, seguinte, no meu banco de dados eu utilizo tipo BLOB, não sei se existe esta tipagem no sql server.
Acredito que o erro está ocorrendo pois o tamanho do arquivo é grande, e isto vem em contrapartida a tipagem que você definiu.
Só para você ter uma ideia, quando crio uma tabela com o tipo blob no firebird, defino o tamanho dela, como este exemplo:
CREATE TABLE TESTE (
IMAGEM BLOB SEGMENT SIZE 4096);
O 4096 é o tamanho máximo do campo, se exceder, retornará erro.
A solução mais simples é criar um novo arquivo com o tamanho limitado, ex: imagem em 800x600 na extensão jpg.
Você também pode definir o tamanho do arquivo que o usuário pode carregar, agora é só usar a criatividade.
Acredito que o erro está ocorrendo pois o tamanho do arquivo é grande, e isto vem em contrapartida a tipagem que você definiu.
Só para você ter uma ideia, quando crio uma tabela com o tipo blob no firebird, defino o tamanho dela, como este exemplo:
CREATE TABLE TESTE (
IMAGEM BLOB SEGMENT SIZE 4096);
O 4096 é o tamanho máximo do campo, se exceder, retornará erro.
A solução mais simples é criar um novo arquivo com o tamanho limitado, ex: imagem em 800x600 na extensão jpg.
Você também pode definir o tamanho do arquivo que o usuário pode carregar, agora é só usar a criatividade.
Luiz,
Será que a limitação não é por causa da versão Express??? Nessa rotina que eu te enviei, não encontrei limite de tamanho. Eu fiz um sistema de HelpDesk para uma empresa e eles tinha problemas justamente com o tamanho do arquivo e com essa rotina tudo foi solucionado. Faça o seguinte.
1 - No SQL mesmo, insira o código abaixo:
2 - Faça o Insert manualmente também:
Obs.: No lugar do caminho do BULK, use o caminho desse arquivo que vc não esta conseguindo salvar no banco. Lembrando que é o caminho onde o SQL consegue enxergar( seu servidor).
Se isso não funcionar, vamos saber que é limitação do banco de dados Express. Agora, se funcionar, você vai ter que alterar a sua rotina de [Ô]salvamento[Ô] para algo do tipo.
Será que a limitação não é por causa da versão Express??? Nessa rotina que eu te enviei, não encontrei limite de tamanho. Eu fiz um sistema de HelpDesk para uma empresa e eles tinha problemas justamente com o tamanho do arquivo e com essa rotina tudo foi solucionado. Faça o seguinte.
1 - No SQL mesmo, insira o código abaixo:
CREATE TABLE dbo.HelpDesk_Imagem
(
ID_Imagem int NOT NULL IDENTITY (1, 1),
Descricao varchar(50) NOT NULL,
Arquivo varbinary(MAX) NOT NULL
) ON [PRIMARY]
TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE dbo.HelpDesk_Imagem ADD CONSTRAINT
PK_HelpDesk_Imagem PRIMARY KEY CLUSTERED
(
ID_Imagem
) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
2 - Faça o Insert manualmente também:
INSERT INTO HelpDesk (ID_Chamado, Descricao, Arquivo)
SELECT
1 AS ID_Chamado
,[ô]Teste[ô] AS Descricao
, * FROM OPENROWSET (BULK [ô]\\data3\Arquivos \HelpDesk\Imagem_Temp\MVREGCLEAN.txt[ô], SINGLE_BLOB) AS Arquivo
Obs.: No lugar do caminho do BULK, use o caminho desse arquivo que vc não esta conseguindo salvar no banco. Lembrando que é o caminho onde o SQL consegue enxergar( seu servidor).
Se isso não funcionar, vamos saber que é limitação do banco de dados Express. Agora, se funcionar, você vai ter que alterar a sua rotina de [Ô]salvamento[Ô] para algo do tipo.
Tópico encerrado , respostas não são mais permitidas