none
Ayuda!!! - Como leer y descargar archivos SQL Server - VB Net RRS feed

  • Pregunta

  • Tengo esto:

    Lo que deseo es que cuando selecciono la fila y al dar click en Leer y/o Descargar  este archivo se pueda leer o descargar segun sea el caso, no se como hacer eso no entiendo.

    Lo guardo asi:

    Private Sub btnGuardar_Click(sender As Object, e As EventArgs) Handles btnGuardar.Click
            If txtRegistro.Text.Trim().Length = 0 Or
                Fecha.Text.Trim().Length = 0 Or
                txtRuta.Text.Trim().Length = 0 Or
                txtNombre.Text.Trim().Length = 0 Or
                txtArchivador.Text.Trim().Length = 0 Or
                CboArea.Text.Trim().Length = 0 Then
                MessageBox.Show("Complete los campos")
                Exit Sub
            End If
    
            Dim resultado As Boolean = False
            Dim Myfile As System.IO.FileStream
            Myfile = System.IO.File.OpenRead(Me.txtRuta.Text)
            Dim Arr(Myfile.Length) As Byte
    
            Using cnx As New SqlConnection(ConfigurationManager.ConnectionStrings("cnxString").ToString())
                If contador_para_guardar = 1 Then
                    cnx.Open()
                    Try
                        Myfile.Read(Arr, 0, Myfile.Length)
                        Dim textosqIngresar As String = (CType("Insert into Archivos (NumReg,Descripcion,Categoria,Archivador,Fecha,Documento,Detalle,PcName)values(@1,@2,@3,@4,@5,@6,@7,@8)", Char()))
                        Dim cmda As New SqlCommand(textosqIngresar, cnx)
    
                        Dim misBytes() As Byte = File.ReadAllBytes(ar)
    
                        cmda.Parameters.AddWithValue("@1", Me.txtRegistro.Text)
                        cmda.Parameters.AddWithValue("@2", Me.txtNombre.Text)
                        cmda.Parameters.AddWithValue("@3", Me.CboArea.Text)
                        cmda.Parameters.AddWithValue("@4", Me.txtArchivador.Text)
                        cmda.Parameters.AddWithValue("@5", Me.Fecha.Text)
                    
                        cmda.Parameters.AddWithValue("@6", misBytes)
                        cmda.Parameters.AddWithValue("@7", Me.txtDetalle.Text)
                        cmda.Parameters.AddWithValue("@8", Principal.slPCNAME.Text)
    
                        If cnx.State = ConnectionState.Open Then
                            cmda.ExecuteNonQuery()
                        End If
                        resultado = True
                        cnx.Close()
                        CType(MdiParent, Principal).showProgress()
                        MsgBox("Datos Guardados")
    
                        oCommandBuilder = New SqlCommandBuilder(Me.oDataAdapter)
                        oDataAdapter = New SqlDataAdapter("Select Id,NumReg,Descripcion from Archivos Order By Id",
                       cnx)
                        oDataTable = New DataTable
                        oDataAdapter.Fill(oDataTable)
                        dgvDocumento.DataSource = oDataTable
                        pre = 0
                        Desactivo()
                        contador_para_guardar = 0
                    Catch ex As Exception
                        MsgBox(ex.Message)
                    End Try
                    Call Limpiar()
                End If
                Return
            End Using
        End Sub

    Boton descargar no tengo echo nada y boton leer me sale error:

    No se puede convertir un objeto de tipo 'System.Int32' al tipo 'System.Byte[]'.

     Private Sub btnDigitalizar_Click(sender As Object, e As EventArgs) Handles btnDigitalizar.Click
            
            Using cnx As New SqlConnection(ConfigurationManager.ConnectionStrings("cnxString").ToString())
                cnx.Open()
    
                Try
                    Dim ds As New DataTable
                    Dim Ide As Integer = dgvDocumento.Item(0, dgvDocumento.CurrentRow.Index).Value
                    Dim da As New SqlDataAdapter("Select Id from Archivos WHERE Id= " & Ide, cnx)
                    da.Fill(ds)
                    Dim f As DataRow = ds.Rows(0)
                    Dim misBytes() As Byte = f.ItemArray(0)
                    File.WriteAllBytes(0, misBytes)
                Catch ex As Exception
                    Throw
                End Try
            End Using
            
        End Sub

    Espero de su ayuda, aun no se si al dar doble click en la fila este se lea o usar boton leer boton descargar no he echo nada, Guardo todo tipo de archivos es por ello que la imagen he colocado pruebas de ahora la cosa es leerlo y verificar que realmente se guarda. y descargarlos.

    Gracias

    miércoles, 29 de marzo de 2017 15:34

Respuestas

  • Si la extensión no está salvada en la base de datos, no hay ninguna forma sencilla de obtenerla; habría que aplicar una heurística sobre los bytes del archivo para los tipos de archivo conocidos.

    Pero si la extensión la tienes salvada en la base de datos, entonces es bastante fácil:

    Dim extension As String = myRow("NombreDelCampo")
    '...
    Dim sFile As String = ((GenerarNombreFichero() + extension))
    

    Evidentemente, donde pone "NombreDelCampo" tienes que poner el nombre de la columna de la tabla en la que guardaste la extensión. Recuerda interponer un "." si no está salvado en la tabla.

    • Propuesto como respuesta Willams Morales jueves, 30 de marzo de 2017 19:47
    • Marcado como respuesta Javier Roque jueves, 30 de marzo de 2017 23:11
    jueves, 30 de marzo de 2017 18:49
  • Ahora me falta hacer el botón descargar

    No, no te falta. Ya lo tienes hecho.

    Fíjate en la parte donde haces el fs.Write(...). Eso ya te descarga el fichero. Simplemente donde preparas el sFile y le pones un nombre "temporal", en lugar de eso ponle un nombre de fichero "bueno", que tenga la ruta del directorio donde quieres salvar la descarga. Y en el momento en que ejecutas el fs.Write ya te deja el fichero descargado ahí. El resto (la parte donde haces el Process y llamas al Start) simplemente suprímelo, suponiendo que no quieras abrir el fichero después de descargarlo.

    • Marcado como respuesta Javier Roque jueves, 30 de marzo de 2017 23:10
    jueves, 30 de marzo de 2017 21:18
  • El sitio donde ponerlo es antes de llamar a Dim fs As New FileStream(AquiElNombreDelArchivo, FileMode.Create).

    En donde pone "AquiElNombreDelArchivo", lo que haces es ponerle la variable donde hayas guardado lo que te haya devuelto el SaveFileDialog.

    Para llamar al SaveFileDialog, se pone algo parecido a lo siguiente (modificando las propiedades para que muestre lo que quieras presentarle al usuario, lo que viene a continuacion es solo un ejemplo):

        Dim saveFileDialog1 As New SaveFileDialog()
    
        saveFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*"
        saveFileDialog1.FilterIndex = 2
        saveFileDialog1.RestoreDirectory = True
    
        If saveFileDialog1.ShowDialog() = DialogResult.OK Then
            Dim nombreFichero As String = saveFileDialog1.FileName
            'Aqui tomas ese nombreFichero y se lo pasas al fs y ejecutas el resto de tu codigo existente
        End If


    viernes, 31 de marzo de 2017 10:33

Todas las respuestas

  • Nadie? O no esta claro?
    jueves, 30 de marzo de 2017 0:51
  • No se puede convertir un objeto de tipo 'System.Int32' al tipo 'System.Byte[]'.

    Este error es razonablemente sencillo de explicar. Fíjate que haces "Select Id from..." y luego tomas f.ItemArray(0). ¿Qué valor te va a devolver eso? Pues el Id, claro está. Presumiblemente, el Id es un Integer. Si lo intentas meter en MisBytes() (que es un array de bytes), te sale el error que estás viendo, que dice que no se puede convertir el Integer en array de bytes.

    Llegados a este punto, la solución debería ser completamente evidente: No hay que hacer un "Select Id..." sino "Select ElCampoApropiado...", siendo "ElCampoApropiado" el campo de tu base de datos que contiene los bytes que quieres salvar.

    jueves, 30 de marzo de 2017 6:45
  • Buenas Tardes he realizado la modificacion de la tabla y codigo ahora almaceno la extension mi pregunta es como jalo la extension? lo que esta en negrita como obtengo estoy nulo ahorita, cuando jalo sin colocar la concatenacion de extension sea .pdf o el que sea si lo especifico lo abre pero la idea es que tengo archivos de varios tipos de extension sino lo hago me crea un archivo sin extension y no puede abrirse.

    Tengo este codigo:  Si en lugar de "Extension" pongoi .pdf prefecto 

    Como tomo la columna Extension?

    Private Sub btnLeer_Click(sender As Object, e As EventArgs) Handles btnLeer.Click
    
            Using cnx As New SqlConnection(ConfigurationManager.ConnectionStrings("cnxString").ToString())
                cnx.Open()
    
                Try
    
                    Dim da As New SqlDataAdapter("Select * From Archivos", cnx)
                    Dim MyCB As SqlCommandBuilder = New SqlCommandBuilder(da)
                    Dim ds As New DataSet()
    
                    da.Fill(ds, "Archivos")
                    Dim myRow As DataRow
                    myRow = ds.Tables("Archivos").Rows(0)
    
                    Dim MyData() As Byte
                    MyData = myRow("Documento")
    
                    Dim K As Long
                    K = UBound(MyData)
                    Dim sFile As String = ((GenerarNombreFichero() + "Extension"))
                    Dim fs As FileStream = New FileStream(sFile, FileMode.Create)
                    fs.Write(MyData, 0, K)
                    fs.Close()
                    Dim obj As System.Diagnostics.Process = New System.Diagnostics.Process
                    obj.StartInfo.FileName = sFile
                    obj.Start()
    
                    fs = Nothing
                    MyCB = Nothing
                    ds = Nothing
                    da = Nothing
                    If cnx.State = ConnectionState.Open Then
                        cnx.Close()
                    End If
                Catch ex As Exception
                    Throw
                End Try
            End Using
    
        End Sub
    Enlazando el dgv con la caja de extension puedo colcoar + txtExtension.text y lo abre pero para el caso de pdf, para el caso de documentos office sale archivo dañado al igual si son imagenes solo va bien si es pdf ;que soluciones puedo obtener?




    jueves, 30 de marzo de 2017 17:24
  • Si la extensión no está salvada en la base de datos, no hay ninguna forma sencilla de obtenerla; habría que aplicar una heurística sobre los bytes del archivo para los tipos de archivo conocidos.

    Pero si la extensión la tienes salvada en la base de datos, entonces es bastante fácil:

    Dim extension As String = myRow("NombreDelCampo")
    '...
    Dim sFile As String = ((GenerarNombreFichero() + extension))
    

    Evidentemente, donde pone "NombreDelCampo" tienes que poner el nombre de la columna de la tabla en la que guardaste la extensión. Recuerda interponer un "." si no está salvado en la tabla.

    • Propuesto como respuesta Willams Morales jueves, 30 de marzo de 2017 19:47
    • Marcado como respuesta Javier Roque jueves, 30 de marzo de 2017 23:11
    jueves, 30 de marzo de 2017 18:49
  • mmm estoy haciendo lo indicado seleccionando la fila 4 pero me abre el primero que contiene un pdf si selecciono la fila 2 o 3 o cualquier otro me abre el primero campo, raro. 

    Respecto a la extension 

    Dim ext As String = Path.GetExtension(OfdDoc.FileName)

    Tengo eso y lo guardo en el campo Extensión, me toma el .

    Alli esta mi tabla y algunos datos para que puedan observar


     Cuando lo tenia asi: Dim sFile As String = ("tmp" + GenerarNombreFichero() + (txtExtension.Text))

    si abre lo que selecciono pero mientras no es pdf  sale dañado es bastante raro ya que lo que me propones es similar.

    jueves, 30 de marzo de 2017 20:08
  • He modificado y añadido algo:

     Dim i As Integer = Me.dgvDocumento.CurrentRow.Index
      myRow = ds.Tables("Archivos").Rows(i)
    El pdf lo abre la imgen de igual forma pero los documento office no salen dañados

    jueves, 30 de marzo de 2017 20:51
  • Ahora analizando eso he realizado otro cambio tenia esto:

    fs.Write(MyData, 0, K)

    Lo cambie por:

    fs.Write(MyData, 0, Convert.ToInt32(MyData.Length))

    con esto ahora si ya me abre el documento word y para descargar como se hace?

    Por lo tanto el codigo del boton leer es asi:

    Private Sub btnLeer_Click(sender As Object, e As EventArgs) Handles btnLeer.Click
    
            Using cnx As New SqlConnection(ConfigurationManager.ConnectionStrings("cnxString").ToString())
                cnx.Open()
    
                Try
                    Dim i As Integer = Me.dgvDocumento.CurrentRow.Index
                    Dim da As New SqlDataAdapter("Select * From Archivos", cnx)
                    Dim MyCB As SqlCommandBuilder = New SqlCommandBuilder(da)
                    Dim ds As New DataSet()
    
                    da.Fill(ds, "Archivos")
                    Dim myRow As DataRow
                    myRow = ds.Tables("Archivos").Rows(i)
    
                    Dim MyData() As Byte
                    MyData = myRow("Documento")
    
                    Dim extension As String = myRow("Extension")
    
                    Dim K As Long
                    K = UBound(MyData)
    
                    Dim sFile As String = ((GenerarNombreFichero() + extension))
                    Dim fs As FileStream = New FileStream(sFile, FileMode.Create)
                    fs.Write(MyData, 0, Convert.ToInt32(MyData.Length))
                    fs.Close()
                    Dim obj As System.Diagnostics.Process = New System.Diagnostics.Process
                    obj.StartInfo.FileName = sFile
                    obj.Start()
    
                    fs = Nothing
                    MyCB = Nothing
                    ds = Nothing
                    da = Nothing
                    If cnx.State = ConnectionState.Open Then
                        cnx.Close()
                    End If
                Catch ex As Exception
                    Throw
                End Try
            End Using
        End Sub

    Para quien luego le sirva

    Ahora me falta hacer el botón descargar


    jueves, 30 de marzo de 2017 20:57
  • Ahora me falta hacer el botón descargar

    No, no te falta. Ya lo tienes hecho.

    Fíjate en la parte donde haces el fs.Write(...). Eso ya te descarga el fichero. Simplemente donde preparas el sFile y le pones un nombre "temporal", en lugar de eso ponle un nombre de fichero "bueno", que tenga la ruta del directorio donde quieres salvar la descarga. Y en el momento en que ejecutas el fs.Write ya te deja el fichero descargado ahí. El resto (la parte donde haces el Process y llamas al Start) simplemente suprímelo, suponiendo que no quieras abrir el fichero después de descargarlo.

    • Marcado como respuesta Javier Roque jueves, 30 de marzo de 2017 23:10
    jueves, 30 de marzo de 2017 21:18
  • Bueno voy analizar me supongo voy a tener que usar el control savefiledialog? para acoplarlo alli o no?
    jueves, 30 de marzo de 2017 21:51
  • [...] voy a tener que usar el control savefiledialog?
    No necesariamente. El SaveFileDialog permite preguntarle al usuario cuál es la ruta en la que quiere salvar el archivo. Pero según cómo tengas diseñado tu programa podría funcionar de otra forma. Por ejemplo, hay programas que tienen una opción en el menú para introducir la carpeta de descargas. Una vez configurada, cada vez que van a salvar un fichero lo envían automáticamente a esa carpeta sin preguntarle la ubicación al usuario. No digo que este sea el mejor diseño para tu programa, simplemente lo pongo como ejemplo para demostrar que no es forzoso usar el SaveFileDialog, también podrías determinar la ruta del fichero de otras formas diferentes.
    jueves, 30 de marzo de 2017 22:05
  • OK. mira he echo esto si me lo descarga pero mmm la verdad ni cuenta me doy  que lo descargo.

     Dim fs As New FileStream("D:\Archivo" + extension, FileMode.Create)

    Asi cualquera sea el archivo le asigna ese nombre si es un excel si es un word o imagen mmm si si es el mismo archivo se sobrescribe sin notificarmelo entonces como que no se ve decente pero si hago esto:

    Dim fs As New FileStream("D:\" + GenerarNombreFichero() + extension, FileMode.Create)
    MessageBox.Show("Archivo a sido descargado en la Unidad D:\")

    Se generan nombres sin sobreescribir el ya realizado creo que se vera mejor si uno el campo Descripcion y en base a este se genera,

    El problema es que descarga me sale el aviso descargado pero  yo preferia me salga un mensaje para elegir el nombre, Al menos se a logrado lo requerido muchas gracias.



    jueves, 30 de marzo de 2017 22:16
  •  se vera mejor si uno el campo Descripcion y en base a este se genera

    Efectivamente, si dispones del nombre del archivo es preferible que lo uses al grabarlo. De lo contrario es mejor que se lo preguntes al usuario.

    Adicionalmente, puedes usar la función System.IO.File.Exists(...) para comprobar si ya existe el archivo en disco, y en ese caso avisar al usuario y preguntar si quiere sobreescribirlo.

    El problema es que descarga me sale el aviso descargado pero  yo preferia me salga un mensaje para elegir el nombre

    En ese caso, es mejor que uses el SaveFileDialog, que te permite escoger el nombre interactivamente.

    viernes, 31 de marzo de 2017 6:50
  • Ok, Tienes un  ejemplo como poner el savedialog he intentado pero no se en que parte colocarlo. para poner la condicion si existe y de paso me salga la pregunta donde guardar o con que nombre.

    Saludos

    viernes, 31 de marzo de 2017 8:36
  • El sitio donde ponerlo es antes de llamar a Dim fs As New FileStream(AquiElNombreDelArchivo, FileMode.Create).

    En donde pone "AquiElNombreDelArchivo", lo que haces es ponerle la variable donde hayas guardado lo que te haya devuelto el SaveFileDialog.

    Para llamar al SaveFileDialog, se pone algo parecido a lo siguiente (modificando las propiedades para que muestre lo que quieras presentarle al usuario, lo que viene a continuacion es solo un ejemplo):

        Dim saveFileDialog1 As New SaveFileDialog()
    
        saveFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*"
        saveFileDialog1.FilterIndex = 2
        saveFileDialog1.RestoreDirectory = True
    
        If saveFileDialog1.ShowDialog() = DialogResult.OK Then
            Dim nombreFichero As String = saveFileDialog1.FileName
            'Aqui tomas ese nombreFichero y se lo pasas al fs y ejecutas el resto de tu codigo existente
        End If


    viernes, 31 de marzo de 2017 10:33
  • Perfecto quedo mucho mejor. He observado algo al momento de leer como decias antes la parte de Leer ya realiza la descarga y efectivamente lo hace sin yo darme cuenta y lo aloja en la carpeta debug que parte del codigo esta ocasionando eso?

    es esto: 

    Dim fs As FileStream = New FileStream(sFile, FileMode.Create)

    Me va generar peso que no deseo solo quiero se lea pero que no lo descarge en interno para ello uso el boton descarga el que indico donde. que modificacion debo hacer para que solo se abra para leer pero que no se descargue en el debug 

    Gracias




    viernes, 31 de marzo de 2017 13:21
  • [...] lo aloja en la carpeta debug que parte del codigo esta ocasionando eso?

    Eso quiere decir que cuando al fs le pasas el fichero, le estas pasando SOLO el fichero, sin anteponerle la carpeta (por ejemplo, pides "fichero.pdf" en lugar de "c:\micarpeta\fichero.pdf"). Esto es bastante mala idea, porque al no indicar la carpeta lo que hace es que lo graba en la carpeta que sea el "Current directory" (directorio actual) del programa. Este resulta ser la carpeta Debug cuando lo ruedas desde dentro de Visual Studio, pero una vez que despliegues el programa en produccion es impredecible cual sera el CurrentDirectory porque depende de la forma en la que el usuario lance el programa (mucha gente piensa que es la misma carpeta en la que se instala el programa, pero no tiene por que ser siempre asi). Por lo tanto, acostumbrate a indicar siempre cual es la carpeta cuando leas o grabes un fichero en disco, nunca pongas solo el nombre del fichero sin anteponerle una carpeta. Puedes usar la carpeta temporal de archivos System.IO.Path.GetTempPath().
    viernes, 31 de marzo de 2017 14:25
  • Pero yo no quiero que cuando le doy click al botón Leer se descargue no hay forma de evitarlo, Para ello tengo el botón Descargar el cual le indico donde quiero se descargue.

    La carpeta temporal que indicas como dice su nombre es temporal supongo se eliminara despues, quizas al salir del sistema este desaparece?

    Bueno lo principal era hacer este formulario para ya luego comenzar el resto pero solo habia notado este detalle, Leer pero que no se descargue.

    viernes, 31 de marzo de 2017 14:41
  • Pero yo no quiero que cuando le doy click al botón Leer se descargue no hay forma de evitarlo,

    Con caracter general, no, no hay forma de evitarlo. El problema es que quieres que se lea con la aplicacion original, por ejemplo, si el archivo es un .doc quieres abrirlo con Word. Pero para eso, es necesario que Word tenga acceso al contenido, sino no puede mostrarlo. Y la unica forma razonable de que word tenga acceso al contenido, es descargandolo a un archivo y luego pasarle ese archivo a Word.

    La carpeta temporal que indicas como dice su nombre es temporal supongo se eliminara despues, quizas al salir del sistema este desaparece?
    No, lo que salves en la carpeta temporal NO se borra por si solo. Tienes que acordarte de borrarlo antes de salir del programa, de lo contrario se queda ahi. De hecho, si vas a la carpeta temporal de tu Windows, y has tenido ese Windows en funcionamiento durante varios meses, seguramente te encontraras cientos o miles de archivos en esa carpeta. De vez en cuando conviene hacer limpieza.
    viernes, 31 de marzo de 2017 16:34
  • Justamente eso  iba decirte  cuando hacemos en ejecutar %temp% nos carga los temporales, entonces podria ser mejor si esa pre - carga que necesita el archivo para ser aperturado se vaya a la carpeta temp de windows? 
    viernes, 31 de marzo de 2017 17:35
  • Sí, eso es lo que yo decía. Cuando descargues el fichero para visualizarlo, es mejor que esto se haga en una carpeta temporal, bien sea el "temp" general de Windows o bien el temp privado en el AppData del usuario. Pero tanto en un caso como en otro, tienes que acordarte luego de borrar el fichero. No se borra solo.
    viernes, 31 de marzo de 2017 19:00
  • Mejor es por la parte de windows eso si de echo debes en cuando si realizo eso de eliminar el temp de windows ademas el ccleaner lo suele realizar.

    Gracias

    viernes, 31 de marzo de 2017 19:07