martes, 16 de febrero de 2010

Descargar el contenido de un DataSet en formato CSV

Esta ejemplo muestra como crear una clase para convertir del contenido de un DataSet a un fichero, con formato CSV, y automatizar su descarga, de manera que en nuestra aplicación ASP.NET podamos integrar esta funcionalidad mediante un control Button o Linkbutton.
El formato CSV (¿Carácteres Separados por Valor?) es reconocido por todos los programas de hoja de cálculo (como MS Excel) y se puede utilizar como orígenes de datos (utilizando por ejemplo MS Text Driver para ODBC) y por lo tanto importar facilmente en cualquier base de datos.
La implementación de esta funcionalidad la hacemos en una clase, un buen nombre sería DataSet2CSV, de esta manera la podremos utilizar facilmente en varios proyectos, compilar por separado y por ejemplo incluirla facilmente en un Servicio Web a utilizar desde múltiples aplicaciones.
Conversión a CSV
La primera funcionalidad de la clase será convertir el contenido del DataSet a formato CSV. Para ello creamos una función, privada a la clase, que reciba el objeto DataSet y genera el contenido del fichero CSV
'Función de Conversión a CSV
Private Function ConvierteCSV(ByRef pDatos As DataSet, _
 Optional ByVal pDelimitadorColumnas As String = ",", _
 Optional ByVal pDelimitadorRegistros As String = vbNewLine) As String    
 
 'Variables Locales
 Dim mSalida As String
 Dim mRegistro As String
 Dim mContadorRegistros As Integer = 0
 Dim mContadorColumnas As Integer = 0
 Dim mValor As String = ""
 Dim mNombreColumna As String = ""
 
 'Solo si hay datos
 If Not IsNothing(pDatos) Then
  If pDatos.Tables.Count > 0 Then
  
   'fila de titulos de columna
   mContadorColumnas = 0
   mRegistro = ""
   'para cada columna
   While mContadorColumnas < pDatos.Tables(0).Columns.Count
   
    mNombreColumna = pDatos.Tables(0).Columns(mContadorColumnas).ColumnName
    
    If mRegistro <> "" Then
     mRegistro = mRegistro & pDelimitadorColumnas
    End If
    
    mValor = """" & mNombreColumna & """"
    mRegistro = mRegistro & mValor
                   
    mContadorColumnas = mContadorColumnas + 1
    
   End While
   mSalida = mSalida & mRegistro
   
   'procesa los registros del dataset
   While mContadorRegistros < pDatos.Tables(0).Rows.Count
    If mSalida <> "" Then
     mSalida = mSalida & pDelimitadorRegistros
    End If
    mRegistro = ""
    mContadorColumnas = 0
    'para cada columna 
    While mContadorColumnas < pDatos.Tables(0).Columns.Count
     If mRegistro <> "" Then
      mRegistro = mRegistro & pDelimitadorColumnas
     End If
     
     mValor = pDatos.Tables(0).Rows(mContadorRegistros)(mContadorColumnas)
     If InStr(mValor, pDelimitadorColumnas) > 0 Then
      mValor = """" & mValor & """"
     End If
     mRegistro = mRegistro & mValor
      mContadorColumnas = mContadorColumnas + 1
    End While
    'añade el registro
    mSalida = mSalida & mRegistro
    mContadorRegistros = mContadorRegistros + 1
   End While
  End If
 End If
       
 Return mSalida
End Function
Automatizar la descarga
Una vez generado el CSV es necesario implementar la descarga del resultado al PC del usuario final.
La siguiente implementación hace que se fuerze la descarga a disco e impide que se visualize el resultado de la conversión a CSV en el propio explorador.
Private Sub DescargaCSV(ByVal pCSV As String, ByVal pNombreCSV As String)
 
 'Obtiene la respuesta actual
 Dim response As System.Web.HttpResponse = System.Web.HttpContext.Current.Response
 
 'Borra la respuesta
 response.Clear()
 response.ClearContent()
 response.ClearHeaders()
 
 'Tipo de contenido para forzar la descarga
 response.ContentType = "application/octet-stream"
 response.AddHeader("Content-Disposition", "attachment; filename=" & pNombreCSV)
 
 'Convierte el string a array de bytes
 Dim buffer(Len(pCSV)) As Byte
 Dim mContador As Long = 0
 While mContador <  Len(pCSV)
  buffer(mContador) = Asc(Mid(pCSV, mContador + 1, 1))
  mContador = mContador + 1
 End While
 
 'Envia los bytes
 response.BinaryWrite(buffer)
 response.End()
 
End Sub
Esta función la podemos utilizar para descargar cualquiero fichero. Si esa fuese nuestra idea sería recomendable hacer una clase propia para esta función con vistas a ampliarla con otras funciones para descargar ficheros existentes en disco, realizar cargas al servidor, etc
..

Interfaz pública de la clase
Para concluir la clase no resta hacer la función publica a través de la cual se va a acceder a las funcionalidades de la clase.
Public Sub EnviaCSV(ByRef pDatos As DataSet, Optional ByVal pNombreFicheroCSV As String = "datos.csv")
 
  'Convirte el DataSet a String en CSV
  Dim mSalida As String
  mSalida = ConvierteCSV(pDatos)
  'Envia el String en CSV
  DescargaCSV(mSalida, pNombreFicheroCSV)
 
 End Sub
Utilizando la clase


Una vez creada nuestra clase vamos a ver como utlizarla desde un formulario ASPX. Por ejemplo suponiendo que nuestro formulario tiene un Datagrid con nombre Datagrid1 y una función CargaDataSet que devuelve un DataSet con los datos a mostrar en el DataGrid. El Load de la página podría ser algo así:
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
  'Introducir aquí el código de usuario para inicializar la página
  If Not IsPostBack Then
   'carga el dataset
   Dim mDatos as DataSet
   mDatos = CargaDataSet() 
 
   'carga el dataset en el datagrid
   DataGrid1.DataSource = mDatos
   DataGrid1.DataBind()
  End If
 End Sub
 
 Private Function CargaDataSet() As DataSet
  '....... 
 End Function
 
Para habilitar la generación y descarga del fichero CSV añadimos un linkbutton LinkButton1
Private Sub LinkButton1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles LinkButton1.Click
  
  'carga el dataset 
  Dim mDatos as DataSet
  mDatos = CargaDataSet() 
  
  'instancia la clase 
  Dim mDescargaCSV as New DataSet2CSV 
  'genera el CSV y lo envia 
  mDescargaCSV.EnviaCSV(mDatos, "NombreFichero.csv")
  
 End Sub 
Al pulsar el Linkbutton se convertirá el dataset a CSV y se mostrará al usuario la típica pantalla de Guardar como ...

No hay comentarios:

Publicar un comentario