Hojas de cálculo en Excel - página principal

Leer un fichero de texto plano

En una entrega anterior, vimos como grabar los datos de una hoja de cálculo en un fichero de texto plano (fichero con extensión "txt"), a través de un macro, de tal forma que el fichero de texto era el destino de nuestros datos. En esta ocasión el fichero de datos será nuestro origen de datos, y lo que haremos será leerlo, sin necesidad de abrirlo directamente (esto no es del todo cierto, porque en realidad tendremos que abrir el fichero, pero esta apertura no será visible, ya que se realizará de forma "interna", a nivel de código de programación).

Para explicarlo más claramente, vamos a suponer que tenemos un fichero de texto plano llamado inversiones 2008.txt, alojado en la misma carpeta donde tenemos el fichero de excel desde el cual queremos leer el texto, y que ese fichero de texto plano presenta los siguientes datos:


Y que queremos leer la línea 5 del fichero, es decir, la línea donde aparece esto:

Instalaciones técnicas               178.000,00

Para poder leer la línea 5 de ese fichero de texto, copiaremos y pegaremos este código en un módulo VBA (como veis, el código está comentado para aclarar las posibles dudas que podíais tener):





Sub leer_linea_de_un_fichero_de_texto()
On Error Resume Next
'Ocultamos el procedimiento
Application.ScreenUpdating = False
'informamos del nombre del fichero de texto
fichero_de_texto = "inversiones 2008.txt"
'Creamos el objeto FileSystemObject
Set fso = CreateObject("Scripting.FileSystemObject")
'Abrimos el fichero. Si el fichero de texto no está
'en la misma ruta que el fichero de excel donde tenemos
'este macro, deberemos poner la ruta, como en este ejemplo:
'Set archivo = fso.OpenTextFile("C:\Mis documentos\" & fichero_de_texto, 1)
'Como supondremos que tenemos el fichero de texto
'en la misma ruta, pondremos esto otro:

ruta = ActiveWorkbook.Path
Set archivo = fso.OpenTextFile(ruta & "\" & fichero_de_texto, 1)
'Cargamos en una variable la línea que queremos leer.
'En el ejemplo, leemos la línea 5, para lo cual nos
'saltaremos las 4 primeras líneas del fichero.

For i = 1 To 4
'nos saltamos 4 líneas
archivo.Skipline
Next 'seguimos con el bucle
'Leemos la línea 5
contenido = archivo.readline()
'Cerramos el fichero
archivo.Close
'Limpiamos los objetos
Set fso = Nothing
Set archivo = Nothing
'Escribimos la línea 5 del fichero en la celda A13
Range("A13") = contenido
'Mostramos el procedimiento
Application.ScreenUpdating = True
End Sub

Pero quizás estés pensando "no, no, …no me interesa leer una línea determinada de un fichero de texto, porque lo que quiero es leer el fichero entero, …¿es esto posible?". Por supuesto que es posible. Si lo que queréis es leer el fichero entero, tan solo tendréis que copiar y pegar este otro macro en un módulo VBA:





Sub leer_fichero_de_texto()
On Error Resume Next
'Ocultamos el procedimiento
Application.ScreenUpdating = False
'informamos del nombre del fichero de texto
fichero_de_texto = "inversiones 2008.txt"
'Creamos el objeto FileSystemObject
Set fso = CreateObject("Scripting.FileSystemObject")
'Abrimos el fichero. Si el fichero de texto no está
'en la misma ruta que el fichero de excel donde tenemos
'este macro, deberemos poner la ruta, como en este ejemplo:
'Set archivo = fso.OpenTextFile("C:\Mis documentos\" & fichero_de_texto, 1)
'Como supondremos que tenemos el fichero de texto
'en la misma ruta, pondremos esto otro:

ruta = ActiveWorkbook.Path
Set archivo = fso.OpenTextFile(ruta & "\" & fichero_de_texto, 1)
'Cargamos en una variable todas las líneas
contenido = archivo.readall
'Cerramos el fichero
archivo.Close
'Limpiamos los objetos
Set fso = Nothing
Set archivo = Nothing
'creamos un array con los datos,
'y los separamos por los intros que haya
'en el fichero de texto (cada "intro" es
'una línea nueva). Tecla intro = vbCrLf

contenido = Split(contenido, vbCrLf)
'empezamos a escribir en la celda A1
Range("A1").Select
'Para todos los elementos del vector...
For i = 0 To UBound(contenido)
'Vamos escribiendo línea a línea
ActiveCell = contenido(i)
'Pasamos a la siguiente línea
ActiveCell.Offset(1, 0).Select
Next 'seguimos con el bucle
'Mostramos el procedimiento
Application.ScreenUpdating = True
End Sub

A partir de ahora, leer un fichero de texto plano, ya no tendrá secretos para vosotros :-)

Desde aquí podéis descargar el fichero de excel junto con el fichero de texto, donde tenéis el ejemplo funcionando.



28 comentarios:

Anónimo dijo...

Muy interesante la macro.
Pero para mis intereses tiene un defecto. La importación la hace toda a una columna (columna A). Lo interesante sería que cada campo lo colocara en distinta columna.
Mi gran duda: como indicar desde excel la ruta del archivo txt a importar sin tener que modificar el codico visual basic.

Muchas gracias por tus macros

José Luis

Javier Marco dijo...

Gracias por tu comentario, pero este ejemplo que he puesto, viene a ser una generalidad, sin tener que entrar en detalles sobre como separar cadenas de texto, en diferentes columnas (por cierto, hay un artículo en el blog que habla de ello). Como no tiene mucho sentido (desde mi punto de vista), separar las cadenas de texto que se importan, en diferentes columnas, por eso lo dejé "todo en una".

Para indicar la ruta del fichero, busca info sobre la propiedad "path".

Salu2

RjveraL dijo...

Muchisimas gracias por tus valiosas ayudas y consejos...

Tengo una duda... mencionabas que había una entrada que hablaba de 'detalles sobre como separar cadenas de texto, en diferentes columnas', mi idea es modificar tu ayuda y agregar agregando esta posibilidad... la idea es importar datos de un archivo de DOS que es tipo de texto Plano y darle los parametros y que me permita importar estos datos en una nueva hoja o un nuevo libro con estos datos ya formateados en columnas...

Podrías decirme cual es la entrada y/o explicar basicamente como se hace esto. Gracias.

Pero es muy valiosa tu ayuda... espero no la dejes de ofrecer... deberias escribir un libro con estos trucos y ayudas...
Aps... si puedes darme el link en mi correo... rjveral@gmail.com es que no siempre ando en esta web ademas veo que es más o menos antiguo esta publicacion.
Rj

Javier Marco dijo...

Hola que tal...

La entrada a la que me refería es esta: separar cadenas de texto.

En este artículo en el que has dejado tu comentario, no he incluido lo de separar en diferentes columnas el texto importado del fichero txt, porque cada caso es un mundo. Igual uno no quiere que se separe cada palabra en una columa, o igual otro quiere que sean cada dos palabras, las que se separen en columnas. Para no establecer un estandar, decidí que lo mejor era mostrar todo en una única columna.

Por cierto, muchas gracias por tu comentario respecto a lo del libro, pero no creo estar a la altura :-)

Anónimo dijo...

Hola, muy buen macro, yo tengo un txt donde tengo varias columnas y varias filas y solo quiero leer algunas filas qe me interesan en funcion de ciertos valores de la columna 1 qe ingreso desde teclado...

muchas gracias

Gustavo

Javier Marco dijo...

Gracias por tu comentario.

Como ves, hay dos macros, uno lee una fila, y el otro el fichero completo. Para leer varias filas, lo mejor es adaptar el primero de ellos.

Seguro que ya lo has hecho ;-)

Un saludo.

Jaass dijo...

Hola

Hace tiempo que quería realizar una macro para leer todos los archivos .txt de un directorio y colocar los datos en una hoja. Gracias a tus macros "ficheros_del_directorio()" y "leer_fichero_de_texto()", por fin se como hacerlo.

Felicidades por el Blog, lo he incluido en favoritos y lo visitaré con regularidad

Saludos
Jaass

Javier Marco dijo...

Hola Jaass. Muchas gracias por tu comentario :-)

Unknown dijo...

Hola Javier, muy útil el código de lectura, pero requiero nuevamente de tu valiosa ayuda. Resulta que tengo un archivo .txt con 700.000 filas y donde las columnas están delimitadas por tabulación, necesito leer este archivo y guardar la información en arreglos para posteriormente realizar cálculos y pasar solo los resultados a Excel. Como verás necesito saber como identificar cada elemento de la fila (que están separadas por tabulación) para guardarlo.

de ante mano muchas gracias por tu ayuda y felicidades por tu blog que es muy útil.

Saludos.

Javier Marco dijo...

Pues dentro de unas semanas tengo pensado explicar un ejemplo parecido.

Como los datos de ese fichero de texto siguen un patrón de conducta, yo no me complicaría la vida, y seleccionaría los datos que te interesan en función de ese patrón. Por ejemplo si en una línea tienes esto:

CODE 3AR453 VALOR 1231243 NUMERO 1B

Y quieres extraer el valor 1231243, ...yo lo que haría es extraer los 7 caracteres que hay a partir del caracter 18 de esa línea, que es precisamente cuando empieza el valor ese que queremos extraer. Con un par de funciones de VBA puedes conseguirlo. Solo es cuestión de aplicar el patrón ese.

Si además de esas líneas, tienes otras con otros datos, puedes hacer un condicional que mire si en la línea que lees, aparecen la cadena de texto "VALOR", y en ese caso, aplicas eso de extraer los 7 caracteres que hay a partir del caracter 18.

Saludos.

Anónimo dijo...

Hola todos,
mi problema es que yo quiero seleccionar el documento de texto que quiero abrir (que cada vez puede ser diferente), para ello uso esto:
dlgAnswer = Application.Dialogs(xlDialogOpen).Show

cuando ejecuto le macro se me abre la ventanita y todo bien pero despues no se seguir, me da error con mi codigo.
Alguien sabe como conseguir que se abra el documento que selecciono?
Muchas gracias

Anónimo dijo...

Hola Javier, vengo siguiendo esta entrada de tu blog unos dias, mirando cada comentario por que lo que me interesa a mi en concreto es poder abrir no solo .txt, sino .doc e incluso .pdf. Con esto tengo la duda de si se podrá hacer lo mismo, por que "creo" que los pdf tienen mas que ver con un archivo de imagen que con uno de texto... ¿Sabes tu si es posible extraer datos de una tabla dentro de un pdf?
EMILIO.

FedeBasic dijo...

Hola.
Mi problema no era de Excel pero tu descripción me ha servido perfectamente para aplicarla en Access y cargar un .txt de ancho fijo en una tabla. Gracias por tu claridad de exposición y por el tiempo que te tomas en enseñar al que no sabe.

Javier Marco dijo...

Muchas gracias por tu comentario Federico.

Realmente motivan mucho, comentarios de este tipo :-)

Anónimo dijo...

Hola Javier,
Estoy intentando hacer una aplicacion que me importe los datos de un xml a las celdas de excel, pueda modificar y luego pueda guardar las modificaciones en xml.La primera parte la logro con cargando como DOMdocument,pero la segunda se me hace completamente imposible por mas que miro ejemplos en foros.

Muchas Gracias por tu Atencion

Oscar

Javier Marco dijo...

Como ya lo han hecho otros, mírate esta página: http://www.meadinkent.co.uk/xl_xml1.htm

Hay un fichero txt con un código de ejemplo.

Un saludo.

Ariel dijo...

Hola Javier
Muy bueno tu blog
Tengo el siguiente problema: los txt (generados como log de un programa que uso) a importar tienen aproximadamente 22000 lineas y resulta que muchas lineas (no salteadas sino como de a bloques)no se cargan con readall. No he podido descubrir analizando las distintas lineas que lo genera. Lo que si descubri que si lo cargo linea a linea no sucede aunque tarda muchisimo y otra cosa llamativa es que si abro el archivo de texto con cualquier editor y lo grabo sin modificarlo a partir de ahi deja de hacer el problema

Anónimo dijo...

Hola, se puede por este metodo que nos da un buen resultado separando por filas, agregarle que tambien separe por columnas ??? por ejemplo:
en una columna: Instalaciones técnicas y en otra columna:178.000,00
y asi que vaya por todo el documento, que pueda valer para mas columnas. muchas gracias.

Javier Marco dijo...

Como columna suelta, no puedes. O bien lees una línea (los ficheros de texto se componen de líneas, no de columnas, aunque estén tabuladas), o bien lees el fichero entero.

En tu caso, yo optaría por leer todo el fichero entero, tal y como es especifica en el 2º código que hay en el artículo, y luego para separar las columnas, utilizaría este otro macro: separar cadenas de texto.

Si quieres, podrías arreglarlo, para tener todo en un solo macro.

Saludos.

FedeBasic dijo...

Esta funcion permite distribuir el texto del fichero txt en 2 columnas, siempre que sepas el numero de caracteres de cada columna. No la he probado porque voy mal de tiempo. Creo que funcionará.Si no funciona lo decis.Saludos.

Function DivideTxt()
Dim fs, f, LineChar As Variant
Dim NomFile, LineStr, ColumnA, ColumnB As String
Dim RowWorkBook, ColWorkBook As Integer

'Ocultamos el procedimiento
Application.ScreenUpdating = False

'El txt estará en el mismo path que el libro Excel en que ponemos este código
NomFile = ActiveWorkbook.Path & "\inversiones 2008.txt"

'Creamos el FSO
Set fs = CreateObject("Scripting.FileSystemObject")

'Creamos el TextStream
Set f = fs.OpenTextFile(NomFile, 1)

'Empezaremos a escribir en la fila 1 de nuestra Hoja
RowWorkBook = 0

'Mientras el AtEndOfLine del TextStream no sea True
Do While Not f.AtEndOfLine
RowWorkBook = RowWorkBook + 1

'Leemos la linea
LineStr = f.ReadLine
'nº de caracteres correspondientes a la primera columna, por ej:46
ColumnA = Mid(LineStr, 1, 46)
'nº de caracteres correspondientes a la segunda columna, por ej:10
ColumnB = Mid(LineStr, 47, 10)

'Escribimos Columna 1
Cells(RowWorkBook, 1).Select
ActiveCell = ColumnA

'Escribimos Columna 2
Cells(RowWorkBook, 2).Select
ActiveCell = ColumnB

fila = ActiveCell.Row
ColumnA = ActiveCell.Column

'Siguiente linea
f.SkipLine
Loop

'Mostramos el procedimiento
Application.ScreenUpdating = True

End Function

Javier Marco dijo...

Gracias por el aporte.

No lo he probado, pero así a bote pronto, creo que eso podría funcionar, siempre y cuando cada columna tuviera el mismo número de caracteres por fila.

Saludos.

JuanPa Condezo dijo...

hola!! que tal Javier! muy bueno tu blog! me sirvio bastante --demasiado!-- este ejemplo.

Pero --siempre los peros-- como alguien comentó y tu respondiste,
quiero extraer cierta cadena y dices que con cierta funcion de VBA se puede... pero cual?
La verdad necesito esa funcion
soy nuevo en esto y no conozco mucho sobre las funciones de vba
y te agradeceria mucho, que si lo sabes, me proporciones el dato sobre esa funcion, ya que tengo muchos reportes en ficheros y tengo que copiar los datos a un consolidado pero tengo que obviar ciertas cadenas.
Me imagino que para leer cada archivo con los reportes tendria que hacer un bucle para que lea cada archivo --si supieras la cantidad de lineas que contiene cada archivo =)-- me gustaria que me ayudes un poquitin de como podria leer cada archivo
de antemano, muchas gracias!

JQ

Anónimo dijo...

CRR. Buenas noches, me funciono perfectamente tu codigo en Excel 2010. Muchas gracias por tu aporte.

Carlos Ardila dijo...

Me gustaria saber como aplicar estas macros para un archivo plano que yo se que los primeros 3 carateres es una columna, los siguientes 2 caracteres son otra columna, los siguientes 30 caracteres es otra columna... y asi sucesivamente.

Es decir que divida cada columna en los caracteres que yo le diga.. .Gracias de antemano.

FedeBasic dijo...

Hoy he tenido un pequeño contratiempo: he convertido un informe Access en una hoja Excel. Hasta ahí sin problemas. Pero el informe tenía varios niveles de agrupamiento y en la Hoja Excel aparecían unos botoncitos con un + y un - que, al pulsarlos, contraian o desplegaban el nivel de agrupamiento. No es mala cosa, en principio, pero, en mi caso he estimado que crearía confusión al cliente. Y ahora mi aportación.¿Cómo quitar los botoncitos y devolver a la Hoja Excel su aspecto "de siempre"? En la barra de Menú pulsar:Datos.Agrupar y Esquema.Borrar Esquema. Es una chorrada pero a mi me ha hecho perder una hora. Un saludo

Anónimo dijo...

Cómo haría para pasar los datos a una hoja de excel de manera que me muestren los datos en una columna determinada del block de notas pero QUE LOS MUESTRE todos a la derecha, es decir si son 10 caracteres y el numero es 15008; no mostrarlo como:
15008..... (5 espacios libres al final) sino como .....15008 (5 espacios libres al inicio) x favor espero puedan ayudarme!!! mi correo es: caov_1987@hotmail.com

Muchas Gracias!

FedeBasic dijo...

Esta función justifica a la derecha el texto de las celdas y rellena cada subcadena de la línea del fichero de texto con tantos espacios como le falte a la celda para ocupar el máximo de caracteres de la columna. A mi me ha funcionado.
Sub DoTextFile()
Dim fsObj, newTextFile As Object, myRange As Range
Dim numCols, numRows, col, row, maxChar, cellNumChar As Long
Dim textCol, strLine As String, aMaxCharCol() As Long


'creamos el archivo de texto en el que escribiremos
Set fsObj = CreateObject("Scripting.FileSystemObject")
Set newTextFile = fsObj.CreateTextFile("C:\Temp\newTextFile.txt", True)

'Vamos a la celda 1,1
Cells(1, 1).Select

'asignamos el area que contiene datos a un objeto Range
'y obtenemos el nº de columnas y filas
Set myRange = Range(Selection, ActiveCell.SpecialCells(xlLastCell))
With myRange
numCols = .Columns.Count
numRows = .Rows.Count
End With
Set myRange = Nothing

'por cada columna hallamos el nº de caracteres de la cadena más larga
'y lo escribimos en un array con tantos elementos como columnas hay
ReDim aMaxCharCol(1 To numCols)

For col = 1 To numCols
maxChar = 0
For row = 1 To numRows
Cells(row, col).Select
cellNumChar = Len(CStr(ActiveCell.Text))
maxChar = IIf(cellNumChar > maxChar, cellNumChar, maxChar)
Next
aMaxCharCol(col) = maxChar
Next

'Ya sabemos cual es es número máximo de caracteres por columna.
'Para alinear el texto de la celda a la derecha añadiremos tantos espacios
'como resulten de restar este número máximo de la longitud del texto de la celda
For row = 1 To numRows
strLine = ""
For col = 1 To numCols
Cells(row, col).Select
'añadimos espacios en blanco de la columna, segun la longitud del texto
textCol = Space(aMaxCharCol(col) - Len(CStr(ActiveCell.Text))) & ActiveCell.Text
strLine = strLine & textCol & Space(2)
Next
'Quitamos los 2 espacios de la ultima columna. Añadimos un caracter de nueva línea
'y escribimos la linea en el fichero de texto
strLine = Left(strLine, Len(strLine) - 2) & vbNewLine
newTextFile.write (strLine)
Next

'una vez finalizado el barrido cerramos el fichero de texto
newTextFile.Close
Set newTextFile = Nothing
Set fsObj = Nothing

End Sub
Un saludo

Javier Marco dijo...

Gracias por la aportación, fedebasic.