Cómo leer un archivo de texto delimitado por comas
Por Enrique Martínez Montejo
Última revisión: 25/06/2006
 

Frecuentemente me suelo encontrar en los grupos de noticias, mensajes de programadores que desean leer un archivo de texto delimitado por comas (los famosos archivos con extensión *.csv), utilizando el proveedor de datos  OLE DB .NET, en un equipo con una configuración regional de español. Lo mismo se estarán preguntando ¿qué tiene que ver un archivo de texto delimitado por comas, con la configuración regional existente en Windows? Aunque parezca mentira, sí tiene que ver, y bastante, hasta tal punto que seremos incapaces de leerlo, debido a que obtendremos el siguiente mensaje de error:

Como todos ustedes conocerán bien, la configuración regional de español utiliza la coma como símbolo de separador decimal, tanto para los números como para la moneda, por lo que el ISAM instalable de texto del motor Microsoft Jet, es incapaz de leer un archivo de texto delimitado por comas si el símbolo de separador decimal coincide también con la coma, por lo que nos veremos obligados a modificar la configuración regional existente, seleccionando cualquier otra que contemple otro símbolo para el separador decimal (como bien podría ser una configuración de inglés de Estados Unidos), o bien modificar mediante programación dichos separadores decimales.

No soy una persona que anime a cambiar la configuración regional, porque nuestras aplicaciones, en todo momento debe respetar escrupulosamente la configuración regional que tiene establecida el usuario, y es nuestra aplicación la que se debe de adaptar a la misma; nunca al contrario. Pero en ocasiones, no nos queda más remedio que modificarla el tiempo suficiente que nos lleve ejecutar una acción, como es el caso que nos ocupa, restaurándola a sus valores originales, una vez efectuada la acción.

Y en esto consiste el ejemplo que a continuación detallo, el cual utiliza las funciones API  GetLocaleInfo y SetLocaleInfo, para obtener y modificar, respectivamente, la configuración regional existente. Para ello, al comienzo de nuestra clase Form, escribiremos las declaraciones de ambas funciones:

Imports System.Data
Imports System.Data.OleDb
Imports System.Runtime.InteropServices

<DllImport("kernel32", CharSet:=CharSet.Auto)> _
Private Shared Function GetLocaleInfo( _
    ByVal locale As Integer, _
    ByVal lCType As Integer, _
    ByVal lpLCData As String, _
    ByVal cchData As Integer) As Integer
        ' Sin código de implementación
End Function

<DllImport("kernel32", CharSet:=CharSet.Auto)> _
Private Shared Function SetLocaleInfo( _
    ByVal locale As Integer, _
    ByVal lCType As Integer, _
    ByVal lpLCData As String) As Integer
        ' Sin código de implementación
End Function 

A continuación, en el evento Click de cualquier botón de comando, llevaríamos a efecto la lectura del archivo de texto de la siguiente manera:

Private Sub Button1_Click(ByVal sender As Object, _
                          ByVal e As EventArgs) Handles Button1.Click

    Dim sepDecimal1, sepDecimal2 As String
    Const LOCALE_USER_DEFAULT As Integer = &H400

    Try
        ' Guardamos el valor del separador decimal.
        '

        Dim buffer As String = New String(CChar(" "), 100)
        GetLocaleInfo(LOCALE_USER_DEFAULT, &HE, buffer, 99)
        sepDecimal1 = buffer.Substring(buffer.IndexOf(" "c) - 2, 1)

        ' Establecemos el nuevo separador decimal.
        '

        SetLocaleInfo(LOCALE_USER_DEFAULT, &HE, ".")

        ' Guardamos el valor del separador decimal monetario.
        '

        buffer = New String(CChar(" "), 100)
        GetLocaleInfo(LOCALE_USER_DEFAULT, &H16, buffer, 99)
        sepDecimal2 = buffer.Substring(buffer.IndexOf(" "c) - 2, 1)

        ' Establecemos el nuevo separador decimal monetario.
        '

        SetLocaleInfo(LOCALE_USER_DEFAULT, &H16, ".")

        ' Configuramos la conexión con el archivo de texto.
        '

        Using cnn As New OleDbConnection( _
                "Provider = Microsoft.Jet.OLEDB.4.0;" & _
                "Data Source=C:\Mis documentos;" & _
                "Extended Properties='TEXT;HDR=Yes;'"
)

            ' Creamos un objeto Command para seleccionar
            ' el archivo de texto que deseamos abrir.
            '

            Dim cmd As OleDbCommand = cnn.CreateCommand()
            cmd.CommandText = "Select * From Archivo#csv"

            ' Configuramos el adaptador de datos.
            '   

            Dim da As New OleDbDataAdapter(cmd)

            ' Creamos un nuevo objeto DataTable.
            '

            Dim dt As New DataTable("ArchivoDeTexto")

            ' Rellenamos el objeto DataTable.
            '

            da.Fill(dt)

            ' Mostramos los registros en un control DataGridView.
            '

            DataGridView1.DataSource = dt

        End Using

    Catch ex As OleDbException
        MessageBox.Show(ex.Errors(0).Message, _
                        "Abrir archivo de texto", _
                        MessageBoxButtons.OK, _
                        MessageBoxIcon.Exclamation)

    Catch ex As Exception
        MessageBox.Show(ex.Message, _
                        "Abrir archivo de texto", _
                        MessageBoxButtons.OK, _
                        MessageBoxIcon.Exclamation)

    Finally
        ' Restablecemos el separador decimal.
        SetLocaleInfo(LOCALE_USER_DEFAULT, &HE, sepDecimal1)

        ' Restablecemos el separador decimal monetario.
        SetLocaleInfo(LOCALE_USER_DEFAULT, &H16, sepDecimal2)

    End Try

End Sub

 

Cómo leer un archivo de texto delimitado por comas

Observarán que he incluido en el bloque Finally, el proceso de restaurar a su valores originales los símboles de separación decimales, de ésta forma nos aseguramos que los mismos se restauren, aunque se produzca cualquier excepción.

Como nuestro archivo de texto utiliza la coma para delimitar los campos, deberemos hacer uso de un archivo de configuración de esquema, que necesariamente se llamará Schema.ini, y que debe residir en la misma carpeta donde se encuentre el archivo de texto que deseamos leer, por tanto, siguiendo el ejemplo, crearemos el archivo Schema.ini, en la carpeta C:\Mis documentos, con la siguiente configuración mínima:

[Archivo.csv]
ColNameHeader=True
CharacterSet=ANSI
Format=CSVDelimited

 

Otros enlaces de interés:

Trabajar con los datos existentes en un archivo de texto

Cómo crear un archivo de texto delimitado con los datos existentes en un DataSet

Indice de Ejemplos de ADO .NET


Enrique Martínez Montejo - 2006

NOTA: La información contenida en este artículo, así como el código fuente incluido en el mismo, se proporciona COMO ESTÁ, sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo explicado, recomendado o sugerido en el presente artículo.

NOTE: The information contained in this article and source code included therein, is provided AS IS without warranty of any kind, and confers no rights. You assume any risk to implement, use or run it explained, recommended or suggested in this article.