Cómo leer archivos planos con ADO.NET (versión Visual Basic 2005)

jueves 13 de diciembre de 2007

Hace poco más de un año escribí este artículo que describe una técnica para leer archivos planos utilizando el OleDB provider de ADO.NET.  Es uno de los artículos de este sitio que ha recibido más comentarios, y entre ellos está uno que dejó fredy que me hizo re-hacer el ejemplo en Visual Basic 2005 para comprobar que no fuera un error de código—en realidad él hizo la mayor parte de la chamba para "traducir" la rutina.

No voy a explicar mucho la lógica del código—para eso te dejo de tarea que leas el artículo original—aquí simplemente te comparto cómo se vería la rutina en VB:

Imports System.IO
Imports System.Data
Imports System.Data.OleDb
 
Module Utilerias
   Public Enum TipoDeArchivoPlano
        Delimited
        Fixed
   End Enum
 
   Public Function LeerArchivoPlano(ByVal archivo As FileInfo, _
        ByVal tieneEncabezado As Boolean, _
        ByVal tipoDeArchivo As TipoDeArchivoPlano) As DataTable
 
        If (Not archivo.Exists) Then
            Throw New FileNotFoundException("No se encontró el archivo especificado")
        End If
 
        Dim conEncabezado As String = IIf(tieneEncabezado, "YES", "NO")
 
        Dim connectionString As String = _
            String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};" + _
            "Extended Properties='text;HDR={1};FMT={2}'", _
            archivo.DirectoryName, conEncabezado, tipoDeArchivo.ToString())
 
        Dim dt As DataTable = New DataTable("miTabla")
 
        Using conn As OleDbConnection = New OleDbConnection(connectionString)
            Using da As OleDbDataAdapter = New OleDbDataAdapter( _
               "SELECT * FROM " + archivo.Name, conn)
 
               da.Fill(dt)
            End Using
        End Using
 
        Return dt
   End Function
End Module

Para probarla, hice una aplicación sencilla en ASP.NET que mostrara los datos de un archivo .CSV que está dentro de un subdirectorio del sitio web.

El archivo jason.csv contiene:

Producto,Cantidad,Precio
Sierra eléctrica,1,250
Máscara de hockey,1,15.50
Machete,5,2.70
Detergente para ropa (con quita-manchas),1,10
Delantal,2,7.25
Afilador,3,5

La página dentro de la solución que en realidad solo tiene un GridView.  Este es el contenido de Default.aspx:

<%@ Page Language="VB" AutoEventWireup="false" 
   CodeFile="Default.aspx.vb" Inherits="_Default" %>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
   <title>Leer un archivo plano con VB 2005</title>
</head>
<body>
   <form id="miFormulario" runat="server">
   <div>
        <asp:GridView ID="miGridView" runat="server">
        </asp:GridView>
   </div>
   </form>
</body>
</html>

Finalmente, para mandar llamar la rutina y bindear—¿enlazar?—los datos al GridView, solo agregué esto en el code-behind:

Partial Class _Default
   Inherits System.Web.UI.Page
 
   Protected Sub miFormulario_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
        Handles miFormulario.Load
 
        If Not Page.IsPostBack Then
            Dim archivo As FileInfo = _
               New FileInfo("D:\WebSites\LeerArchivosPlanosVB\Archivos\jason.csv")
 
            Dim tabla As New DataTable
            tabla = Utilerias.LeerArchivoPlano(archivo, True, TipoDeArchivoPlano.Delimited)
 
            If tabla.Rows.Count > 0 Then
               miGridView.DataSource = tabla
               miGridView.DataBind()
            Else
               Response.Write("No hay datos para mostrar.")
            End If
 
        End If
   End Sub
End Class

El resultado de correr la página:

 

Whew! Funcionó smile_teeth

Enjoy. smile_shades


PD.  Puedes descargar el código de este ejemplo del sitio de la Comunidad .NET de Cd. Juárez.

categorías: , , , ,

7 comentarios:

  1. MKPopper dijo:

    Hola, muy bueno tu codigo lo encontre excelente, pero te quisiera hacer una consulta, como se puede hacer cuando el archivo no esta delimiado por comas, si no que por algun otro caracter, como punta y coma (;) o tabulado, etc. Es posible decirle al FTM el caracter delimitador. O en su defecto antes de leer el archivo, cambiar o reemplazar el caracter que tenga, ya sea ; o tab, por comas para asi poder leer bien el archivo.

  2. KaMiKaZe aka Carlos dijo:

    Sí es posible. Para un archivo delimitado por ";" creo que puedes hacerlo utilizando un archivo schema.ini (de manera similar a como se hizo con el de posiciones fijas en el artículo original).

    El contenido del archivo schema.ini podría ser algo como esto:

    [miarchivodelimitadoporpuntoycoma.txt]
    ColNameHeader=True
    Format=Delimited(;)
    Col1=Producto Char Width 40
    Col2=Cantidad Long
    Col3=Precio Double


    No sé si poniendo FMT=Delimited(;) en el string de conexión también funcione.

    Espero te sirva

  3. "" dijo:

    Hola muchas gracias por el artículo. ¿¿Sería posible que al escribir "una,palabra,entre,comillas" evitara el delimitador??

  4. Carlos Rubalcava dijo:

    Anónimo--
    No necesitas nada especial para que evite el delimitador cuando el texto está entre comillas.

    Por ejemplo, si tu archivo .CSV tiene este contenido:
    Cantidad,Producto,Precio
    1,"Sierra electrica",250
    1,"Máscara, de, hockey",15.50
    5,"Machete",2.70
    1,"Detergente para ropa con, quita-manchas",10
    2,"Delantal",7.25
    3,"Afilador",5

    La rutina lo lee perfectamente (al menos en las pruebas que yo hice).

    Si de plano se te pone muy rebelde, podrías utilizar un archivo schema.ini para "forzar" que lo lea como un CSV delimitado. El schema.ini podría verse así:

    [miarchivo.csv]
    ColNameHeader=True
    Format=CSVDelimited

    Y si se sigue poniendo necio, pues entonces ya te sugeriría cambiar el caracter delimitador (usando, por ejemplo ";" como mencioné en uno de los comentarios anteriores).

    Espero te sirva.

  5. Anónimo dijo:

    Cordial Saludo, estoy probando tu ejemplo y esta excelente pero a mi me sale con un pequeño error que todos los datos del archivo ya sea csv o plano salen todos en una columna......

  6. Carlos Rubalcava dijo:

    Las broncas de que no te traiga correctamente los datos (especialmente cuando contienen muchas columnas) las he visto porque las columnas de texto contienen comas como parte de los datos. Lo mismo se hacen pelotas el Excel o Access (ambos usan el mismo driver de OleDb que el ejemplo del artículo, detrás de las cámaras). En este caso lo que debes asegurarte es que las columnas de texto estén delimitado por comillas.

    Agregar un schema.ini también ayuda mucho a asegurar que se lea el tipo de dato correcto por cada columna.

    Espero te ayude

  7. Carlos Rubalcava dijo:

    Para los que están teniendo el problema de que sus datos aparecen en una sola columna:

    Parece que Diego Bernal ya le atinó con algunas cosas para resolverlo. Yo le hice el comentario que si tienes campos tipo fecha a veces son latosos (porque en "español" y en "inglés" se leen distinto, p.ej. 05/06/2008 es 6 de mayo en EE.UU. pero es 5 de junio en países hispanos). En fin, les copio aquí su mensaje:

    "Carlos Cordial Saludo. Escribo para decir que ya pude llenar el dataset completamente con columnas y todo, gracias a tus consejos me puse a indagar profundamente en archivos txt, csv, y schemas.ini. En síntesis mi problema era con el idioma de mi sistema operativo , las comillas me sirvieron en muchos campos pero implicaba hacer un trabajo extra pero el ( ; ) sirvió perfectamente .Me tope con un excelente articulo el cual me llevo por otros caminos en cuanto al trabajar con archivos de este tipo y me encontré con muchas características tales como se ven en este articulo:

    http://www.mvp-access.es/softjaen/articulos/texto/jet_text_isam.htm#Index21

    De pronto hace una simbiosis perfecta con tu articulo y puede ayudar a mucha gente que tiene mi problema de pronto si quieres hacer un síntesis y complementar tu gran articulo que me sirvió bastante para realizar mi aplicación.

    De Nuevo Gracias por la atención y la ayuda .

    Diego Fernando Bernal B.
    Desde Colombia."


    PD. También pudiera serles útil la página de referencia sobre schema.ini en MSDN (parece que cambió desde que escribí el artículo)

    Espero les ayude