none
schema.ini RRS feed

  • Pregunta

  • Saludos cordiales a todos.

    Tengo estas dudas para realizar un pequeño proyecto.

    De un sistema externo (Oracle) se descargan archivos en formato de texto (.TXT) delimitado por ";"

    Lo que quiero hacer es realizar una aplicación con VB.NET y Access (uso la versión 2003) para que importe a Access el archivo descargado y en Access se depure dicho archivo y posteriormente darle salida a Excel con el formato requerido. Mis dudas son:

    Tengo que crear un archivo (schema.ini), según lo que he leído este archivo debe de estar en el origen de donde se va a jalar el archivo de texto.

    Es correcto esto? Pero que pasa cuando el usuario guarda el archivo descargado en otra ruta donde no esta el schema.ini, ya que el usuario tiene la libertad de guardar el archivo que descarga en cualquier ruta de su PC. Existe alguna opción de importar el archivo de texto a Access sin importar que en ese origen no este el schema.ini.

    Mi otra duda es la BDD Access, debería de agregarla al proyecto o alojarla en algún lugar de la PC para su funcionamiento.

    Espero a ver sido claro, y puedan ayudarme a aclarar mis dudas.

    Saludos

    DS


    Aprendiz de todos maestro de nadie. Saludos desde Cd. Juarez Chihuahua Mexico. DS.

    viernes, 11 de marzo de 2016 5:55

Respuestas

  • "Dany Solis" preguntó:

    > De un sistema externo (Oracle) se descargan archivos en formato de texto (.TXT) delimitado por ";"
    >
    > Tengo que crear un archivo (schema.ini), según lo que he leído este archivo debe de estar en el
    > origen de donde se va a jalar el archivo de texto.
    >
    > Es correcto esto?

    Totalmente correcto. El archivo de información de esquema (Schema.ini) tiene que estar en LA MISMA CARPETA que contiene el archivo de texto delimitado que quieres leer. Es decir, si el archivo de texto se encuentra en la carpeta C:\NombreCarpeta\Carpeta1\, ahí es donde también deberá residir el archivo Schema.ini.

    > Pero que pasa cuando el usuario guarda el archivo descargado en otra ruta donde no esta
    > el schema.ini, ya que el usuario tiene la libertad de guardar el archivo que descarga
    > en cualquier ruta de su PC.

    Me parece estupendo que el usuario tenga plena libertad para guardar el archivo de texto donde estime conveniente, pero si en la carpeta donde lo ha guardado no existe un archivo Schema.ini, va a ser complicado que posteriormente puedas leer satisfactoriamente un archivo de texto delimitado por el carácter de ";" mediante el ISAM de texto del motor Microsoft Jet o Microsoft ACE.

    Si no haces uso de un archivo Schema.ini, tendrías que modificar el registro de Windows, y no voy a ser yo el que te aconseje hacer eso.

    Por ejemplo, si vas a trabajar con el proveedor de datos Microsoft.Jet.OLEDB.4.0, tendrías que modificar el valor Format existente en la siguiente clave:

        HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\Engines\Text

    para que se quede con el siguiente valor:

        Format        Delimited(;)

    ya que el valor predeterminado es CSVDelimited (archivo de texto separado por comas).

    Es por ese motivo que para leer un archivo de texto separado por ";", o utilizas un archivo Schema.ini o modificas el valor de la clave del registro indicada, siempre y cuando utilices algún tipo de ISAM de texto, claro está.

    Si tu sistema operativo Windows es de 64 bits, tienes que buscar la clave en el subsistema WOW6432Node:

       HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Jet\4.0\Engines\Text

    ya que el proveedor Microsoft.Jet.OLEDB.4.0 solamente está soportado para 32 bits, lo que implica que tu proyecto de Visual Basic .NET tendrás que compilarlo, sí o sí, para que se ejecute en modo de 32 bits.

    > Existe alguna opción de importar el archivo de texto a Access sin
    > importar que en ese origen no este el schema.ini.

    ¿Te refieres a si Visual Studio tiene alguna opción para realizar tal importación? Si es así, te diré que no tiene una opción para ello.

    Para más información sobre el archivo Schema.ini en particular, y sobre el ISAM de texto en general, te remito a la lectura del siguiente artículo:

    Trabajar con los datos de un archivo de texto

    > Mi otra duda es la BDD Access, debería de agregarla al proyecto o
    > alojarla en algún lugar de la PC para su funcionamiento.

    Al igual que los usuarios tienen libertad para descargar el archivo de texto donde les plazca, la misma libertad tienes para agregar la base de datos a tu proyecto de Visual Basic o alojarla en cualquier otra carpeta de tu PC. ;-)

    > Te comparto una imagen del archivo de texto

    Si el contenido de la imagen pertenece al archivo de texto con el que deseas trabajar, te diré que en principio NO SE TRATA de un archivo de texto delimitado, porque para ello tendrías que eliminar las 10 primeras líneas, y comenzar por aquellas que parece ser que contiene el nombre de los campos o columnas:

        Before Final Group;Before Immediate Group; ...

    Y también observo que posteriormente hay una línea en blanco. ¿?

    Por supuesto, si no deseas eliminar las líneas de cabecera, entonces tendrás que indicar en las propiedades extendidas de la cadena de conexión que la primera línea del archivo NO CONTIENE el nombre de los campos:

        Dim cadenaConexion As String = _
          "Provider=Microsoft.Jet.OLEDB.4.0;Extended Properties='TEXT;HDR=No';Data Source=C:\NombreCarpeta"

    Y posteriormente, en la consulta SQL de selección tendrás que hacer uso de una cláusula WHERE para seleccionar aquellos registros donde el primer campo, por ejemplo, no sea NULL (tenga algún valor):

        objetoCommand.CommandText = "SELECT * FROM [NombreArchivo#txt] WHERE NOT ISNULL(F1)"

    Fíjate que al no utilizar los nombres de los campos, el primer campo se llamará F1, el segundo F2, el tercer F3, etc.

    Con independencia que el archivo Schema.ini tenga que estar alojado o no en la misma carpeta que contiene el archivo de texto, me parece a mí que va a ser complicado que puedas trabajar desde tu aplicación de Visual Basic, utilizando el ISAM de texto de los proveedores Microsoft Jet o Microsoft ACE, con el contenido del supuesto "archivo delimitado" que aparece en la imagen que has publicado. ;-)

    ¡Suerte!


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, 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 recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.





    viernes, 11 de marzo de 2016 15:46
    Moderador
  • "Dany Solis" escribió:

    > Hasta ahora no se que me ira mejor si tratar de desarrollar la aplicación
    > en VB.NET o tratar de automatizar la aplicacion de Access.

    Si el archivo de texto SIEMPRE va a tener la misma estructura, es muy sencillo importar los datos a Access sin tener que depurarlos previamente con Excel, porque tampoco es necesario que elimines las 10 primeras filas ejecutando la consulta SQL que te he indicado en mi respuesta anterior. Tan solo tienes que crear en tiempo de ejecución el archivo Schema.ini en la misma carpeta donde el usuario ha decidido guardar el archivo de texto, porque en definitiva se trata de crear y guardar la estructura del archivo de texto delimitado en un simple archivo de texto.

    Si lo deseas probar, inserta en tu proyecto los siguientes procedimientos:

    Import System.Data.OleDb
    
        ''' <summary>
        ''' Importa a una base de datos de Access un archivo de texto delimitado.
        ''' </summary>
        ''' <param name="rutaArchivoTexto">Ruta completa del archivo de texto delimitado.</param>
        ''' <param name="rutaBaseAccess">Ruta completa de la base de datos de Access.</param>
        ''' <param name="nombreTabla">Nombre de la tabla del archivo de Access.</param>
        ''' <returns></returns>
        Friend Shared Function ImportarArchivo(rutaArchivoTexto As String, rutaBaseAccess As String, nombreTabla As String) As Integer
    
            ' Comprobar los valores de los parámetros.
            '
            If (String.IsNullOrWhiteSpace(rutaArchivoTexto)) Then
                Throw New ArgumentException("No se ha especificado la ruta del archivo de texto delimitado.")
            End If
    
            If (Not IO.File.Exists(rutaArchivoTexto)) Then
                Throw New IO.FileNotFoundException("No existe el archivo de texto en la ruta indicada.")
            End If
    
            If (String.IsNullOrEmpty(rutaBaseAccess)) Then
                Throw New ArgumentException("No se ha especificado la ruta del archivo de Access.")
            End If
    
            If (Not IO.File.Exists(rutaBaseAccess)) Then
                Throw New IO.FileNotFoundException("No existe el archivo de Access en la ruta indicada.")
            End If
    
            If (String.IsNullOrWhiteSpace(nombreTabla)) Then
                Throw New ArgumentException("No se ha especificado el nombre de la tabla de Access.")
            End If
    
            Dim rutaSchemaIni As String = String.Empty
    
            Try
                ' Obtener solamente el nombre del archivo de texto.
                Dim nombreArchivo As String = IO.Path.GetFileName(rutaArchivoTexto)
    
                ' Obtener solamente la ruta de la carpeta
                Dim rutaCarpeta As String = IO.Path.GetDirectoryName(rutaArchivoTexto)
    
                ' Crear el archivo Schema.ini
                rutaSchemaIni = CreateSchemaIni(rutaCarpeta, nombreArchivo)
    
                ' Crear la cadena de conexión con la base de datos de Access.
                Dim cadenaConexion As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & rutaBaseAccess
    
                ' Establecer una conexión con la base de Access.
                Using cnn As New OleDbConnection(cadenaConexion)
    
                    ' Crear el comando
                    Dim cmd As OleDbCommand = cnn.CreateCommand()
    
                    ' Construir la consulta SQL de creación de tabla
                    cmd.CommandText = String.Format("SELECT * INTO [{0}] FROM [{1}] " &
                                                    "IN ''[TEXT; DATABASE={2}] WHERE NOT ISNULL(IdCliente)",
                                                    nombreTabla, nombreArchivo, rutaCarpeta)
                    ' Abrir la conexión
                    cnn.Open()
    
                    ' Ejecutar la consulta delvolviendo el número de registros importados.
                    Return cmd.ExecuteNonQuery()
    
                End Using
    
            Finally
                ' Eliminar siempre el archivo Schema.ini. No se
                ' producirá una excepción si el archivo no existe.
                '
                IO.File.Delete(rutaSchemaIni)
    
            End Try
    
        End Function
    
        ''' <summary>
        ''' Crea un archivo Schema.ini temporal en la carpeta que
        ''' contiene la ruta del archivo de texto especificado.
        ''' </summary>
        ''' <param name="path">Ruta de la carpeta donde se creará el archivo Schema.ini.</param>
        ''' <param name="nombreArchivoTexto">Nombre y extensión del archivo de texto.</param>
        ''' <remarks></remarks>
        Private Shared Function CreateSchemaIni(path As String, nombreArchivoTexto As String) As String
    
            Dim sb As New Text.StringBuilder()
            sb.AppendFormat("[{0}]{1}", nombreArchivoTexto, Environment.NewLine)
            sb.AppendLine("ColNameHeader=False")    ' La primera fila no contiene el nombre de los campos.
            sb.AppendLine("CharacterSet=ANSI")
            sb.AppendLine("Format=Delimited(;)")    ' Archivo delimitado por el carácter ;
            sb.AppendLine("MaxScanRows=0")
            sb.AppendLine("Col1 = IdCliente Integer")
            sb.AppendLine("Col2 = Nombre Char")
            sb.AppendLine("Col3 = NIF Char")
            sb.AppendLine("Col4 = Domicilio Char")
            sb.AppendLine("Col5 = Poblacion Char")
            sb.AppendLine("Col6 = Provincia Char")
            sb.AppendLine("Col7 = CodPostal Char")
    
            ' Obtener la ruta completa del archivo Schema.ini
            path = IO.Path.Combine(path, "Schema.ini")
    
            ' Proceder a crear el archivo Schema.ini. Se sobrescribirá
            ' cualquier archivo Schema.ini existente.
            '
            Using stream As New IO.StreamWriter(path)
                stream.Write(sb.ToString())
            End Using
    
            ' Devolver la ruta del archivo Schema.ini
            Return path
    
        End Function
    

    El archivo hace uso del proveedor de datos Microsoft.Jet.OLEDB.4.0 porque comentas que tu base de datos tiene formato de Access 2003, pero que si lo deseas, también puedes utilizar el proveedor de datos Microsoft.ACE.OLEDB.12.0. Si te decides por éste último, reemplaza la cadena de conexión por ésta otra:

        ' Crear la cadena de conexión con la base de datos de Access.
        Dim cadenaConexion As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & rutaBaseAccess

    Como el archivo Schema.ini asume que la primera fila del archivo de texto no contiene el nombre de los campos, para que estos no se llamen F1, F2, F3, etc., en el mismo archivo de esquema indicamos el nombre que deseamos que tengan los campos, que en definitiva serán los que tengan en la propia tabla de la base de Access. El ejemplo que aparece en la función CreateSchemaIni, me he limitado a especificar el nombre de 7 campos de una supuesta tabla sencilla de Clientes. Por supuesto, tienes libertad absoluta para especificar los nombres de campos y tipos de datos que estimes conveniente. Pero si modificas el nombre de los campos, también tendrás que modificar la consulta SQL de creación de tabla existente en la función ImportarArchivo:

        ' Construir la consulta SQL de creación de tabla
        cmd.CommandText = String.Format("SELECT * INTO [{0}] FROM [{1}] " &
                                        "IN ''[TEXT; DATABASE={2}] WHERE NOT ISNULL(IdCliente)",
                                        nombreTabla, nombreArchivo, rutaCarpeta)

    Para no tener que eliminar "a mano" las 10 primeras líneas del archivo de texto, tienes que sustituir el nombre  IdCliente por aquel que sepas de antemano que todas sus filas tienen un valor válido (que no sea null). Por ejemplo, ahí podrías especificar el nombre del campo que va a formar la clave principal de la tabla de Access.

    ¡Bueno! Pues cuando quieras importar a Access los datos del archivo de texto delimitado, tan solo ejecutarías lo siguiente:

         Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            Try
                ' Procedemos a importar a un archivo de Access
                ' los datos existentes en un archivo de texto
                ' delimitado por el carácter ;.
                '
                Dim n As Integer = ImportarArchivo("C:\NombreCarpeta\Archivo.txt", "C:\Mis documentos\bd1.mdb", "NombreTabla")
                MessageBox.Show(String.Format("Se han importado satisfactoriamente {0} registros.", n))
    
            Catch ex As Exception
                ' Se ha producido un error.
                MessageBox.Show(ex.Message)
    
            End Try
    
        End Sub
    

    Observa que a la función ImportarArchivo le paso las rutas fijas donde se encuentran tanto el archivo de texto como la base de datos de Access. Como comentas que el usuario es libre para guardar el archivo de texto donde mejor le plazca, tendrás que preguntarle al usuario dónde ha guardado el archivo de texto, porque tampoco es cuestión que nuestra aplicación tenga que conocer en qué carpeta lo ha guardado.

    Pero esa "pregunta al usuario" ya la dejo en tus manos, para que a éste le muestres un cuadro de diálogo y que pueda seleccionar el archivo de texto delimitado que desea importar a la base de Access. Por supuesto, si el usuario también es libre de seleccionar la base de datos de Access, tendrías que hacer lo mismo para preguntarle qué base de datos de Access deseas utilizar.

    Por último indicarte que se producirá una excepción si ya existe en la base de datos de Access seleccionada una tabla con el mismo nombre que hemos especificado a la hora de importar los datos, cuestión que es normal que ello suceda.

    Como podrás observar, no necesitas para nada utilizar Microsoft Excel como herramienta intermedia para transferir los datos del archivo de texto delimitado a una base de datos de Access. Y referente al archivo Schema.ini, tan solo tienes que crearlo y eliminarlo cuando haya realizado su trabajo. Como verás, es cuestión de "coser y cantar". ;-)

    Adapta el ejemplo a tus necesidades.


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, 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 recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.

    sábado, 12 de marzo de 2016 8:07
    Moderador

Todas las respuestas

  • Hola:
    Tanto el archivo txt, como el mdb pueden estar en cualquier sitio que sea accesible desde la maquina donde se esta ejecutando el proceso de carga de datos.
    Lo que no entiendo es:
    >y en Access se depure dicho archivo y posteriormente darle salida a Excel <
    ¿ Que quieres decir con depurar en Access ?
    Si lo que pretendes es teniendo como origen un fichero txt y quieres como fin un archivo xlsx, no te hace falta usar el access como intermediario, se puede hacer "directamente" a traves de las librerias de OpenXml.

    Un saludo desde Bilbo
    Carlos

    viernes, 11 de marzo de 2016 6:57
  • Lo que no entiendo es:
    >y en Access se depure dicho archivo y posteriormente darle salida a Excel <
    ¿ Que quieres decir con depurar en Access ?
    Si lo que pretendes es teniendo como origen un fichero txt y quieres como fin un archivo xlsx, no te hace falta usar el access como intermediario, se puede hacer "directamente" a traves de las librerias de OpenXml.

    A lo que me refiero con depurar en Access es que en Access elimino las columnas que no necesito y registros innecesarios, posteriormente lo envoi a Excel con el format requerido.

    Tanto el archivo txt, como el mdb pueden estar en cualquier sitio que sea accesible desde la maquina donde se esta ejecutando el proceso de carga de datos.

    A ver si entiendo bien esto, si el archivo.txt lo tengo en C:\Archivos y el Schema.ini lo tengo en mi escritorio no habria problemas con la importación del archivo de texto.

    Aunque me suena interesante lo que me comentas usar librerias openxml para tartar el archivo directamente y enviarlo a Excel inmediatamente aunque sinceramente jamas he usado ese tipo de metodos.

    Te comparto una imagen del archivo de texto y la salida que le doy al final en Excel, si tuvieras un ejemplo del uso de las librerias OpenXml para tartar archivos de texto te lo agradeceria, voy a buscar en la WEB a ver si encuentro algun ejemplito.

    Ejemplo

    Saludos

    DS


    Aprendiz de todos maestro de nadie. Saludos desde Cd. Juarez Chihuahua Mexico. DS.

    viernes, 11 de marzo de 2016 15:10
  • En este post tenes unos ejemplos de como leer o escribir un excel, usando OpenXml.

    Saludos,

    Diego

    viernes, 11 de marzo de 2016 15:17
  • "Dany Solis" preguntó:

    > De un sistema externo (Oracle) se descargan archivos en formato de texto (.TXT) delimitado por ";"
    >
    > Tengo que crear un archivo (schema.ini), según lo que he leído este archivo debe de estar en el
    > origen de donde se va a jalar el archivo de texto.
    >
    > Es correcto esto?

    Totalmente correcto. El archivo de información de esquema (Schema.ini) tiene que estar en LA MISMA CARPETA que contiene el archivo de texto delimitado que quieres leer. Es decir, si el archivo de texto se encuentra en la carpeta C:\NombreCarpeta\Carpeta1\, ahí es donde también deberá residir el archivo Schema.ini.

    > Pero que pasa cuando el usuario guarda el archivo descargado en otra ruta donde no esta
    > el schema.ini, ya que el usuario tiene la libertad de guardar el archivo que descarga
    > en cualquier ruta de su PC.

    Me parece estupendo que el usuario tenga plena libertad para guardar el archivo de texto donde estime conveniente, pero si en la carpeta donde lo ha guardado no existe un archivo Schema.ini, va a ser complicado que posteriormente puedas leer satisfactoriamente un archivo de texto delimitado por el carácter de ";" mediante el ISAM de texto del motor Microsoft Jet o Microsoft ACE.

    Si no haces uso de un archivo Schema.ini, tendrías que modificar el registro de Windows, y no voy a ser yo el que te aconseje hacer eso.

    Por ejemplo, si vas a trabajar con el proveedor de datos Microsoft.Jet.OLEDB.4.0, tendrías que modificar el valor Format existente en la siguiente clave:

        HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\Engines\Text

    para que se quede con el siguiente valor:

        Format        Delimited(;)

    ya que el valor predeterminado es CSVDelimited (archivo de texto separado por comas).

    Es por ese motivo que para leer un archivo de texto separado por ";", o utilizas un archivo Schema.ini o modificas el valor de la clave del registro indicada, siempre y cuando utilices algún tipo de ISAM de texto, claro está.

    Si tu sistema operativo Windows es de 64 bits, tienes que buscar la clave en el subsistema WOW6432Node:

       HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Jet\4.0\Engines\Text

    ya que el proveedor Microsoft.Jet.OLEDB.4.0 solamente está soportado para 32 bits, lo que implica que tu proyecto de Visual Basic .NET tendrás que compilarlo, sí o sí, para que se ejecute en modo de 32 bits.

    > Existe alguna opción de importar el archivo de texto a Access sin
    > importar que en ese origen no este el schema.ini.

    ¿Te refieres a si Visual Studio tiene alguna opción para realizar tal importación? Si es así, te diré que no tiene una opción para ello.

    Para más información sobre el archivo Schema.ini en particular, y sobre el ISAM de texto en general, te remito a la lectura del siguiente artículo:

    Trabajar con los datos de un archivo de texto

    > Mi otra duda es la BDD Access, debería de agregarla al proyecto o
    > alojarla en algún lugar de la PC para su funcionamiento.

    Al igual que los usuarios tienen libertad para descargar el archivo de texto donde les plazca, la misma libertad tienes para agregar la base de datos a tu proyecto de Visual Basic o alojarla en cualquier otra carpeta de tu PC. ;-)

    > Te comparto una imagen del archivo de texto

    Si el contenido de la imagen pertenece al archivo de texto con el que deseas trabajar, te diré que en principio NO SE TRATA de un archivo de texto delimitado, porque para ello tendrías que eliminar las 10 primeras líneas, y comenzar por aquellas que parece ser que contiene el nombre de los campos o columnas:

        Before Final Group;Before Immediate Group; ...

    Y también observo que posteriormente hay una línea en blanco. ¿?

    Por supuesto, si no deseas eliminar las líneas de cabecera, entonces tendrás que indicar en las propiedades extendidas de la cadena de conexión que la primera línea del archivo NO CONTIENE el nombre de los campos:

        Dim cadenaConexion As String = _
          "Provider=Microsoft.Jet.OLEDB.4.0;Extended Properties='TEXT;HDR=No';Data Source=C:\NombreCarpeta"

    Y posteriormente, en la consulta SQL de selección tendrás que hacer uso de una cláusula WHERE para seleccionar aquellos registros donde el primer campo, por ejemplo, no sea NULL (tenga algún valor):

        objetoCommand.CommandText = "SELECT * FROM [NombreArchivo#txt] WHERE NOT ISNULL(F1)"

    Fíjate que al no utilizar los nombres de los campos, el primer campo se llamará F1, el segundo F2, el tercer F3, etc.

    Con independencia que el archivo Schema.ini tenga que estar alojado o no en la misma carpeta que contiene el archivo de texto, me parece a mí que va a ser complicado que puedas trabajar desde tu aplicación de Visual Basic, utilizando el ISAM de texto de los proveedores Microsoft Jet o Microsoft ACE, con el contenido del supuesto "archivo delimitado" que aparece en la imagen que has publicado. ;-)

    ¡Suerte!


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, 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 recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.





    viernes, 11 de marzo de 2016 15:46
    Moderador
  • Gracias señor Enrique por la excelente explicación que me dio.

    Como usted lo comenta el archivo de texto pues no lo es porque para ser un archivo delimitado por ";" deberia de eliminar las primeras 10 filas del archivo.

    Actualmente el trabajo se hace así:

    > Se descarga el archivo de texto

    > Se abre con excel separando las columnas por el delimitador ";"

    > Se guarda en Excel

    > Se abre la aplicacion de Access y se importa el archivo ya de Excel

    > En Access se depura el archivo de las primeras 10 filas se toman solo ciertos datos

    > De las siguientes filas también solo se toman ciertos datos que cumplan "X" criterios

    > Ya depurado se envia a Excel y se da formato desde Access

    Esto hasta cierto punto esta automatizado pero como vera se hacen cosas manuales y ese es el trabajo que quiero ahorrar a los usuarios que usan esta aplicación.

    SalidaExcel

    Voy a leer el articulo que tiene publicado en su WEB y daré un vistazo a el uso de las librerias OpenXml.

    Hasta ahora no se que me ira mejor si tratar de desarrollar la aplicación en VB.NET o tratar de automatizar la aplicacion de Access.


    Aprendiz de todos maestro de nadie. Saludos desde Cd. Juarez Chihuahua Mexico. DS.

    sábado, 12 de marzo de 2016 3:58
  • "Dany Solis" escribió:

    > Hasta ahora no se que me ira mejor si tratar de desarrollar la aplicación
    > en VB.NET o tratar de automatizar la aplicacion de Access.

    Si el archivo de texto SIEMPRE va a tener la misma estructura, es muy sencillo importar los datos a Access sin tener que depurarlos previamente con Excel, porque tampoco es necesario que elimines las 10 primeras filas ejecutando la consulta SQL que te he indicado en mi respuesta anterior. Tan solo tienes que crear en tiempo de ejecución el archivo Schema.ini en la misma carpeta donde el usuario ha decidido guardar el archivo de texto, porque en definitiva se trata de crear y guardar la estructura del archivo de texto delimitado en un simple archivo de texto.

    Si lo deseas probar, inserta en tu proyecto los siguientes procedimientos:

    Import System.Data.OleDb
    
        ''' <summary>
        ''' Importa a una base de datos de Access un archivo de texto delimitado.
        ''' </summary>
        ''' <param name="rutaArchivoTexto">Ruta completa del archivo de texto delimitado.</param>
        ''' <param name="rutaBaseAccess">Ruta completa de la base de datos de Access.</param>
        ''' <param name="nombreTabla">Nombre de la tabla del archivo de Access.</param>
        ''' <returns></returns>
        Friend Shared Function ImportarArchivo(rutaArchivoTexto As String, rutaBaseAccess As String, nombreTabla As String) As Integer
    
            ' Comprobar los valores de los parámetros.
            '
            If (String.IsNullOrWhiteSpace(rutaArchivoTexto)) Then
                Throw New ArgumentException("No se ha especificado la ruta del archivo de texto delimitado.")
            End If
    
            If (Not IO.File.Exists(rutaArchivoTexto)) Then
                Throw New IO.FileNotFoundException("No existe el archivo de texto en la ruta indicada.")
            End If
    
            If (String.IsNullOrEmpty(rutaBaseAccess)) Then
                Throw New ArgumentException("No se ha especificado la ruta del archivo de Access.")
            End If
    
            If (Not IO.File.Exists(rutaBaseAccess)) Then
                Throw New IO.FileNotFoundException("No existe el archivo de Access en la ruta indicada.")
            End If
    
            If (String.IsNullOrWhiteSpace(nombreTabla)) Then
                Throw New ArgumentException("No se ha especificado el nombre de la tabla de Access.")
            End If
    
            Dim rutaSchemaIni As String = String.Empty
    
            Try
                ' Obtener solamente el nombre del archivo de texto.
                Dim nombreArchivo As String = IO.Path.GetFileName(rutaArchivoTexto)
    
                ' Obtener solamente la ruta de la carpeta
                Dim rutaCarpeta As String = IO.Path.GetDirectoryName(rutaArchivoTexto)
    
                ' Crear el archivo Schema.ini
                rutaSchemaIni = CreateSchemaIni(rutaCarpeta, nombreArchivo)
    
                ' Crear la cadena de conexión con la base de datos de Access.
                Dim cadenaConexion As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & rutaBaseAccess
    
                ' Establecer una conexión con la base de Access.
                Using cnn As New OleDbConnection(cadenaConexion)
    
                    ' Crear el comando
                    Dim cmd As OleDbCommand = cnn.CreateCommand()
    
                    ' Construir la consulta SQL de creación de tabla
                    cmd.CommandText = String.Format("SELECT * INTO [{0}] FROM [{1}] " &
                                                    "IN ''[TEXT; DATABASE={2}] WHERE NOT ISNULL(IdCliente)",
                                                    nombreTabla, nombreArchivo, rutaCarpeta)
                    ' Abrir la conexión
                    cnn.Open()
    
                    ' Ejecutar la consulta delvolviendo el número de registros importados.
                    Return cmd.ExecuteNonQuery()
    
                End Using
    
            Finally
                ' Eliminar siempre el archivo Schema.ini. No se
                ' producirá una excepción si el archivo no existe.
                '
                IO.File.Delete(rutaSchemaIni)
    
            End Try
    
        End Function
    
        ''' <summary>
        ''' Crea un archivo Schema.ini temporal en la carpeta que
        ''' contiene la ruta del archivo de texto especificado.
        ''' </summary>
        ''' <param name="path">Ruta de la carpeta donde se creará el archivo Schema.ini.</param>
        ''' <param name="nombreArchivoTexto">Nombre y extensión del archivo de texto.</param>
        ''' <remarks></remarks>
        Private Shared Function CreateSchemaIni(path As String, nombreArchivoTexto As String) As String
    
            Dim sb As New Text.StringBuilder()
            sb.AppendFormat("[{0}]{1}", nombreArchivoTexto, Environment.NewLine)
            sb.AppendLine("ColNameHeader=False")    ' La primera fila no contiene el nombre de los campos.
            sb.AppendLine("CharacterSet=ANSI")
            sb.AppendLine("Format=Delimited(;)")    ' Archivo delimitado por el carácter ;
            sb.AppendLine("MaxScanRows=0")
            sb.AppendLine("Col1 = IdCliente Integer")
            sb.AppendLine("Col2 = Nombre Char")
            sb.AppendLine("Col3 = NIF Char")
            sb.AppendLine("Col4 = Domicilio Char")
            sb.AppendLine("Col5 = Poblacion Char")
            sb.AppendLine("Col6 = Provincia Char")
            sb.AppendLine("Col7 = CodPostal Char")
    
            ' Obtener la ruta completa del archivo Schema.ini
            path = IO.Path.Combine(path, "Schema.ini")
    
            ' Proceder a crear el archivo Schema.ini. Se sobrescribirá
            ' cualquier archivo Schema.ini existente.
            '
            Using stream As New IO.StreamWriter(path)
                stream.Write(sb.ToString())
            End Using
    
            ' Devolver la ruta del archivo Schema.ini
            Return path
    
        End Function
    

    El archivo hace uso del proveedor de datos Microsoft.Jet.OLEDB.4.0 porque comentas que tu base de datos tiene formato de Access 2003, pero que si lo deseas, también puedes utilizar el proveedor de datos Microsoft.ACE.OLEDB.12.0. Si te decides por éste último, reemplaza la cadena de conexión por ésta otra:

        ' Crear la cadena de conexión con la base de datos de Access.
        Dim cadenaConexion As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & rutaBaseAccess

    Como el archivo Schema.ini asume que la primera fila del archivo de texto no contiene el nombre de los campos, para que estos no se llamen F1, F2, F3, etc., en el mismo archivo de esquema indicamos el nombre que deseamos que tengan los campos, que en definitiva serán los que tengan en la propia tabla de la base de Access. El ejemplo que aparece en la función CreateSchemaIni, me he limitado a especificar el nombre de 7 campos de una supuesta tabla sencilla de Clientes. Por supuesto, tienes libertad absoluta para especificar los nombres de campos y tipos de datos que estimes conveniente. Pero si modificas el nombre de los campos, también tendrás que modificar la consulta SQL de creación de tabla existente en la función ImportarArchivo:

        ' Construir la consulta SQL de creación de tabla
        cmd.CommandText = String.Format("SELECT * INTO [{0}] FROM [{1}] " &
                                        "IN ''[TEXT; DATABASE={2}] WHERE NOT ISNULL(IdCliente)",
                                        nombreTabla, nombreArchivo, rutaCarpeta)

    Para no tener que eliminar "a mano" las 10 primeras líneas del archivo de texto, tienes que sustituir el nombre  IdCliente por aquel que sepas de antemano que todas sus filas tienen un valor válido (que no sea null). Por ejemplo, ahí podrías especificar el nombre del campo que va a formar la clave principal de la tabla de Access.

    ¡Bueno! Pues cuando quieras importar a Access los datos del archivo de texto delimitado, tan solo ejecutarías lo siguiente:

         Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            Try
                ' Procedemos a importar a un archivo de Access
                ' los datos existentes en un archivo de texto
                ' delimitado por el carácter ;.
                '
                Dim n As Integer = ImportarArchivo("C:\NombreCarpeta\Archivo.txt", "C:\Mis documentos\bd1.mdb", "NombreTabla")
                MessageBox.Show(String.Format("Se han importado satisfactoriamente {0} registros.", n))
    
            Catch ex As Exception
                ' Se ha producido un error.
                MessageBox.Show(ex.Message)
    
            End Try
    
        End Sub
    

    Observa que a la función ImportarArchivo le paso las rutas fijas donde se encuentran tanto el archivo de texto como la base de datos de Access. Como comentas que el usuario es libre para guardar el archivo de texto donde mejor le plazca, tendrás que preguntarle al usuario dónde ha guardado el archivo de texto, porque tampoco es cuestión que nuestra aplicación tenga que conocer en qué carpeta lo ha guardado.

    Pero esa "pregunta al usuario" ya la dejo en tus manos, para que a éste le muestres un cuadro de diálogo y que pueda seleccionar el archivo de texto delimitado que desea importar a la base de Access. Por supuesto, si el usuario también es libre de seleccionar la base de datos de Access, tendrías que hacer lo mismo para preguntarle qué base de datos de Access deseas utilizar.

    Por último indicarte que se producirá una excepción si ya existe en la base de datos de Access seleccionada una tabla con el mismo nombre que hemos especificado a la hora de importar los datos, cuestión que es normal que ello suceda.

    Como podrás observar, no necesitas para nada utilizar Microsoft Excel como herramienta intermedia para transferir los datos del archivo de texto delimitado a una base de datos de Access. Y referente al archivo Schema.ini, tan solo tienes que crearlo y eliminarlo cuando haya realizado su trabajo. Como verás, es cuestión de "coser y cantar". ;-)

    Adapta el ejemplo a tus necesidades.


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, 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 recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.

    sábado, 12 de marzo de 2016 8:07
    Moderador
  • Hola:
    Para el siguiente ejemplo he creado un fichero origen de datos llamado PROVINCIA.TXT con el siguiente contenido

    ID,PROVINCIA,CAPITAL
    1,ALAVA,GASTEIZ
    20,GUIPUZCOA,DONOSTIA
    48,BIZKAIA,BILBO

    En un Form con 1 DataGridView y 1 Button, copia y pega el siguiente codigo.
    ( Tienes que añadir una referencia a la libreria SpreadsheetLight.dll )

    Option Explicit On
    Option Strict On
    Imports System.Data.OleDb
    Imports SpreadsheetLight

    Public Class Form1
        Dim moDataTable As New DataTable("PROVINCIA")

        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
            Me.DataGridView1.AllowUserToAddRows = False
            'Cargar el fichero texto en el datagrid
            Dim lsCadConexionTxt As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & Application.StartupPath & ";Extended Properties='TEXT;HDR=Yes'"
            Try
                Using loConexionTxt As New OleDbConnection(lsCadConexionTxt)
                    ' Construimos la consulta SQL de selección, donde especificaremos el nombre del archivo de texto.
                    Dim lsQuery As String = "Select * From PROVINCIA#txt"
                    ' Construimos un comando para ejecutar la consulta.
                    Using loComando As New OleDbCommand(lsQuery, loConexionTxt)
                        ' Construimos un objeto DataAdapter
                        Dim loDataAdapter As New OleDbDataAdapter(loComando)
                        'para que se vea el tamaño de las columnas
                        loDataAdapter.MissingSchemaAction = MissingSchemaAction.AddWithKey
                        ' Rellenamos un objeto DataTable
                        loDataAdapter.Fill(moDataTable)
                    End Using
                End Using
                Me.DataGridView1.DataSource = moDataTable
            Catch ex As Exception
                MessageBox.Show(ex.Message, "Load", MessageBoxButtons.OK, MessageBoxIcon.Information)
            End Try
        End Sub

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim lDataTable As DataTable = CType(Me.DataGridView1.DataSource, DataTable)
            'Creamos un objeto SqlDocument
            Dim sl As New SLDocument()
            Dim liColumna As Integer = 0
            'Rellenar la primera fila (contiene los nombres de columnas)
            For Each Columna As DataColumn In lDataTable.Columns
                liColumna += 1
                'usamos la función SetCellValue para poblar la celda
                sl.SetCellValue(1, liColumna, Columna.ColumnName)
            Next
            'definimos el indice de la Fila y Columna donde comenzaremos a vaciar los datos
            Dim liFila As Integer = 2
            liColumna = 1
            'Recorremos las filas del datatable
            For Each loFila As DataRow In lDataTable.Rows
                'Recorremos las columnas del datatable
                For liCiclo As Integer = 0 To lDataTable.Columns.Count - 1
                    'comenzamos a enviar los valores al objeto SLDocument, usando el valor de la fila y columna
                    sl.SetCellValue(liFila, liColumna, Convert.ToString(loFila.Item(liCiclo)))
                    liColumna += 1
                Next
                liFila += 1
                liColumna = 1
            Next
            'Guardamos el documento
            sl.SaveAs(Application.StartupPath & "\PROVINCIA.XLSX")
        End Sub
    End Class

    La imagen del Form es


    La imagen del fichero de excel es


    Un saludo desde Bilbo
    Carlos


    lunes, 14 de marzo de 2016 7:28
  • "J. Carlos Herrero" escribió:

    > Para el siguiente ejemplo he creado un fichero origen de datos
    > llamado PROVINCIA.TXT con el siguiente contenido
    >
    > ID,PROVINCIA,CAPITAL
    > 1,ALAVA,GASTEIZ
    > 20,GUIPUZCOA,DONOSTIA
    > 48,BIZKAIA,BILBO
    >
    > ( Tienes que añadir una referencia a la libreria SpreadsheetLight.dll )
    >
    >  'Cargar el fichero texto en el datagrid
    >  Dim lsCadConexionTxt As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" &
    >    Application.StartupPath & ";Extended Properties='TEXT;HDR=Yes'"
    >
    >
    >   'Guardamos el documento
    >   sl.SaveAs(Application.StartupPath & "\PROVINCIA.XLSX")

    Hola, J. Carlos:

    No he tenido la oportunidad de utilizar la librería SpreadsheetLight.dll, pero para crear un archivo de Excel con los datos existentes en un archivo de texto delimitado por comas, me parece a mí que no es necesario escribir tantas líneas de código, y menos aún rellenar un objeto DataTable para posteriormente recorrer sus filas mientras se envían valores a un objeto SLDocument, porque se puede hacer todo directamente.

    Si deseas hacer la prueba para crear un nuevo libro de Excel con el archivo Provincia.txt, simplemente tienes que ejecutar lo siguiente en el evento Click de un control Button:

    Imports System.Data.OleDb
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            Try
                ' Establecer una conexión con el archivo de texto delimitado por comas
                Using cnn As New OleDbConnection()
                    cnn.ConnectionString =
                        "Provider=Microsoft.ACE.OLEDB.12.0;" & _
                        "Extended Properties='TEXT;HDR=Yes';" & _
                        "Data Source=C:\Mis documentos"
    
                    Dim cmd As OleDbCommand = cnn.CreateCommand()
    
                    ' Construir la consulta SQL para crear un nuevo libro de Excel
                    ' con un rango de celdas con nombre llamado Provincias.
                    cmd.CommandText = "SELECT * INTO [Provincias] " & _
                                      "IN ''[Excel 12.0 Xml;DATABASE=C:\Mis documentos\Provincias.xlsx]" & _
                                      "FROM [Provincia#txt]"
    
                    ' Abrimos la conexión.
                    cnn.Open()
    
                    ' Exportamos a Excel los datos del archivo de texto
                    Dim n As Integer = cmd.ExecuteNonQuery()
    
                    MessageBox.Show("Nº de registros expoortados: " & CStr(n))
    
                End Using
    
            Catch ex As Exception
                MessageBox.Show(ex.Message)
    
            End Try
    
        End Sub

    Como podrás observar, tan solo hay que utilizar los ISAM de Texto y de Excel del motor Microsoft ACE. ;-)

    Un saludo


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, 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 recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.


    lunes, 14 de marzo de 2016 8:48
    Moderador
  • Hola:

    Efectivamente es mucho mas rapido y simple con tu ejemplo.
    "Nunca te acostaras sin saber otra cosa mas"

    P.D.

    La librería SpreadsheetLight.dll hace autenticas "virguerías con los ficheros excel

    Un saludo desde Bilbo
    Carlos


    lunes, 14 de marzo de 2016 9:07
  • Gracias por sus aportes explicaciones y comentarios.

    Estoy echando mano de los codigos que me expusieron y voy a realizar las pruebas necesarias.

    Gracias ya comento los resultados.

    Saludos

    DS


    Aprendiz de todos maestro de nadie. Saludos desde Cd. Juarez Chihuahua Mexico. DS.

    martes, 15 de marzo de 2016 13:42