Métodos para contar las líneas de un archivo.

Pregunta Sin Miedo no te cortes cualquier cosa para empezar - Autoit se comienza facilmente.Para Ordenes o Comandos sueltos. Ver nota como preguntar.
Haseo
Mensajes: 15
Registrado: 07 Ago 2011, 08:45

Métodos para contar las líneas de un archivo.

Mensaje por Haseo »

pues a ver, descubrí el error del post anterior, y bueno, la cosa es que tenia puesto FileRead, entonces cuando me encontraba el valor, como no lee líneas, el _StringBetween() no me sirve porque he de especificar la linea... Es decir, me sirve pero necesito saber en que linea están esos valores.

Código: Seleccionar todo

			$array = _FileListToArray($Directorio,"*",1)
			$i = 1
			While $i <= $array[0]
				$File = FileOpen($Directorio & $array[$i])
				$line = FileReadLine($File,LINEA)
				$Result = StringInStr($line, $ValID)
				If $File = -1 Then
				MsgBox(04096, "Error", "Imposible abrir el archivo.")
				Elseif ($Result >= 2 )	Then
					$idsearch = _StringBetween($line, '<item id="', '"')
					$id = $idsearch[0]
					$c = $b + 1
					While $b < $c
					_FileWriteToLine($PathDir,$b,'<item id="1">',0)
					$b = $b + 1
					_FileWriteToLine($PathDir,$b,'<production id="' & $id & '" count="' & $Count1 & '"/>',0)
					$b = $b + 1
					_FileWriteToLine($PathDir,$b,'<ingredient id="' & $ItemIC & '" count="' & $Count2 & '"/>',0)
					$b = $b + 1
					_FileWriteToLine($PathDir,$b,'</item>',0)
					$c = $b
					WEnd
						$b = $b + 2
					ExitLoop
				ElseIf ($i = $array[0]) Then
					MsgBox(0496,"Resultado","No se han encontrado resultados con esa ID o Nombre de Producto.")
					ExitLoop
				Else
					$i = $i + 1
				EndIf
			WEnd
Pues mirad el codigo, así tal cual, obviamente no me busca bien porque al usar FileReadLine necesito especificar la línea de donde se va a buscar, cosa que, como es una busqueda, no sabes donde va a estár el valor. Y no se me ocurre nada para determinar la linea con un array que vaya autoincrementandose o algo parecido... Y si uso FileRead a secas, solo me dice que si, que el valor que estoy buscando se encuentra en TAL ARCHIVO. no en TAL LINEA. y entonces despues el valor de $id me lo da como el principio del nombre del archivo, ya que no especifica línea el FileRead... Dios mio, me va a explotar la cabeza xD
Avatar de Usuario
Chefito
Profesional del Autoit
Mensajes: 2035
Registrado: 21 Feb 2008, 18:42
Ubicación: Albacete/Cuenca (España)

Re: Métodos para contar las líneas de un archivo.

Mensaje por Chefito »

Pues muy facil. Simplemente para saber el número de línea donde está el texto, metes inicialmente una variable que se vaya incrementado en 1 para que te vaya contando las líneas (inicialmente esta variable tiene que estar a 0, para que en el primer incremento valga 1). Luego pones la función filereadline. Inmediatamente después pones una condición (if...then) para que ponga la variable que cuenta las líneas a 0 y se salga del bucle, por si la función filereadline da error (habrá llegado al final y no habrá encontrado nada). Luego introduces el _stringbetween para que busque el texto en cada línea. Y al final del bucle, poner una condición (if...then) diciendo que si _stringbetween encuentra el texto, que se salga del bucle.
Cuando salga del bucle, puedes comprobar la variable que cuenta las líneas. Si vale 0 es que no ha encontrado nada, y si tiene algún valor, es que ha encontrado algo. También se puede saber con el resultado de la función _stringbetween.

Mira los ejemplos de la ayuda que está casi todo puesto. Solamente hay que variarlos un poquito :smt024 .

Saludos.
Cita vista en algún lugar de la red: En este mundo hay 10 tipos de personas, los que saben binario y los que no ;).
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Métodos para contar las líneas de un archivo.

Mensaje por Ximorro »

Ahora que veo cómo has "solucionado" lo del While, te puedo decir que no es necesario.
Tienes que fijarte en la lógica del programa, es como seguir mentalmente el programa:
Haces $c = $b + 1, con lo que $c es mayor que $b (pues siempre vale uno más)
Entonces el While $b < $c la primera vez se cumple siempre.
Antes de acabar el bucle haces $c = $b, con lo que el siguiente While $b < $c no se cumplirá nunca.

Conclusión, no es un bucle, pues sólo se ejecuta una vez. Pero es que tampoco es un condicional, pues tampoco puede ocurrir que no se ejecute. Así que no hay que poner absolutamente nada, ni While, ni If ni nada, es un código normal.

Ya casi lo tienes, encuentras el archivo donde está lo que buscas, que no es poco. Como dice Chefito sólo tienes que contar las líneas a mano y ya está, cada vez que leas una línea la cuentas.
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
Haseo
Mensajes: 15
Registrado: 07 Ago 2011, 08:45

Re: Métodos para contar las líneas de un archivo.

Mensaje por Haseo »

EDIT:

Bien pues, funciona todo perfectamente, pero sigo teniendo un pequeño problema.

El programa tarda unos 23 segundos en encontrar un valor que está en el primer archivo, en la linea 738. ( Y es el item con ID 43, es decir, es de los primeros. )
Lo que quiero decir es que yo soy más rápido buscandolo a mano. Hay alguna manera de hacer que busque más rápido?

Y otra cosa, si el programa está mucho rato buscando, me lo cierra el autoit por protegerme contra el stack overflow, pero por mas que le añado tiempo al sleep mas tarde o mas temprano me lo cierra... Alguna idea?
Avatar de Usuario
Chefito
Profesional del Autoit
Mensajes: 2035
Registrado: 21 Feb 2008, 18:42
Ubicación: Albacete/Cuenca (España)

Re: Métodos para contar las líneas de un archivo.

Mensaje por Chefito »

Si quieres pon el código a ver si es que has hecho algo mal.

Aunque pensando un poco, puede que sea algo lento por todos los accesos que haces línea a línea, buscando línea a línea (encima con _stringbetween), etc. No se.

Otra forma supongo más rápida de hacerlo puede ser cargando los archivos de texto en un control edit (udf guiedit.au3. Funciones que empiezan por _guiedit_) o un richedit (udf guirichedit. funciones que empiezan por _guirichedit_).
Vamos primero con el edit.

Yo probaría esto:

Para sacar el texto que te interesa:

Imagino que sabes abrir un archivo y meter su contenido en una variable (ejemplo, $texto). Ese paso lo saltamos.
Podemos buscar el texto que hay en la variable $texto y saber su posición con stringinstr.
Luego buscamos el texto que te interesa en el texto que contiene la variable $texto. Tu lo has hecho con _stringbetween. Yo te recomiendo que lo intentes con stringregexp. Supongo que sea más rápida. Mira el primer ejemplo de la ayuda y adaptalo a tu código.

Ahora toca saber la línea de golpe y porrazo :smt023 :

Creas un control edit (guictrlcreateedit). Puedes tenerlo oculto si no te interesa que lo vean. Mira la función GUICtrlSetState para ocultarlo.
Luego asignas el texto del fichero ($texto) al control para trabajar con él dentro de este control. Mira guictrlsetdata.
Como ya sabes la posición del texto que buscaste anteriormente (te la dió la función stringinstr), situas el cursor en esta posición con la función _guictrledit_setsel.
Cuando ya lo hayas situado, con controlcommand y su parámetro GetCurrentLine averiguas la línea. Te dejo unos ejemplos de esto mismo de nuestros compañeros Melba23 (mira sobre todo este) y Yashied: http://www.autoitscript.com/forum/topic ... line-edit/

Puede que sea algo lioso, pero prueba a ver. Si te atascas en algo ves preguntando.

También tenemos el richedit que aun puede que sea aun más rápido, ya que directamente puede cargar archivos en su control (_GUICtrlRichEdit_StreamFromFile), buscar textos (_GUICtrlRichEdit_FindText) y saber la línea donde se encuentra el archivo (_GUICtrlRichEdit_GetLineNumberFromCharPos). Juer, si al final puede que este sea más facil! :smt005 .

No se. Mira la ayuda, sus ejemplos y prueba a ver cual te convence más.

Otra forma que me gusta menos pero a lo mejor podría funcionar bien y ser muy rápida, es utilizando el word. Son las funciones de la ayuda que empiezan por _Word. Lo que pasa que para este método tienes que tener el word instalado, logicamente. Y encima que no te de problemas tu versión de word, tu sistema operativo, etc....que te aseguro que te puede dar. Lo digo por experiencia :smt002 . Aunque siempre puedes evitarlos utilizando las propiedades y métodos de los objetos directamente :smt024 .

Saludos.
Cita vista en algún lugar de la red: En este mundo hay 10 tipos de personas, los que saben binario y los que no ;).
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Métodos para contar las líneas de un archivo.

Mensaje por Ximorro »

Huuum, otra manera rápida sería usar el comando FIND del shell DOS. Ahí el problema es capturar la salida estándar para ver el resultado, o más fácilmente mandarlo a un archivo y leerlo al final.

Pero de todas maneras sería interesante que nos mostraras el código, si es posible simplificado al tema de la búsqueda, y si no son cosas privadas pásanos también los archivos donde se busca, para que hagamos pruebas.

Tarda mucho así que algo raro debe estar pasando, ¿de qué volumen de datos hablamos? ¿cuántos archivos de cuántas líneas? Y otra cosa ¿accedes a ellos directamente en el disco duro local o es por red? Si es por red puede haber otros retrasos, incluso puede ir más lento si son muchos archivos pequeños que pocos grandes.
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
Avatar de Usuario
Chefito
Profesional del Autoit
Mensajes: 2035
Registrado: 21 Feb 2008, 18:42
Ubicación: Albacete/Cuenca (España)

Re: Métodos para contar las líneas de un archivo.

Mensaje por Chefito »

Ximorro escribió:Huuum, otra manera rápida sería usar el comando FIND del shell DOS. Ahí el problema es capturar la salida estándar para ver el resultado, o más fácilmente mandarlo a un archivo y leerlo al final.
Muy buena idea!. No sabía que ese comando de búsqueda tenía un parámetro para que te dijese la línea donde había encontrado el texto. Pienso que esto va a ser lo más rápido y facil. Yo lo intentaría con este método.

Luego se me ocurrió otro, pero puede que siga siendo algo lento. Cargar todo el texto en una variable, buscarlo y obtener la posición con stringinstr. Esto es lo facil. Para encontrar la línea se tendría que hacer una función donde le pasases como parámetros el texto y la posición anterior. Esta función hiría recorriendo todo el texto con stringinstr, buscando los saltos de línea (@lf). Cada vez que encontrase un salto se incrementaría un contador de líneas. Esto hasta llegar a la posición pasada. Por supuesto se hiría cambiando el parámetro start con la nueva posición encontrada con stringinstr más uno. Y así continuamente hasta llegar a la posición pasada (un bucle).

Sería muy facil de implementar, pero no se lo que tardaría en hacer el recuento de líneas.

Saludos.
Cita vista en algún lugar de la red: En este mundo hay 10 tipos de personas, los que saben binario y los que no ;).
Haseo
Mensajes: 15
Registrado: 07 Ago 2011, 08:45

Re: Métodos para contar las líneas de un archivo.

Mensaje por Haseo »

bueno, pues he probado con las cosas que me dijo Chefito al principio, y no se si es que no lo entendí, o que no funcionó... Ni idea. El StringRegExp me devuelve 0.

Bueno, subo todo lo relacionado con el programa como dijo Ximorro. Sobre la cantidad de lineas por archivo, y la cantidad de archivos...
183 archivos, ponle que de minimo, 1020 líneas cada uno.

Enlace: http://www.megaupload.com/?d=1NETVBFW

Yo seguiré intentandolo...

Donde va a parar, es MUCHÍSIMO más rapido así:

Código: Seleccionar todo

	ShellExecute("C:\WINDOWS\System32\cmd.exe")
	WinWait("C:\WINDOWS\System32\cmd.exe")
	Send('find /I /N "' & $ReadIDP & '" "' & $Directorio & $array[$i] & '" >> C:\string.txt')
	Send("{Enter}")
El wooden helmet, que esta en la linea 738, es darle a enter y PLAF, encontrado.

Ahora mi pregunta es... ¿ Cómo podría hacer que la ventana de la Shell se quede hideada, y al darle a Enter despues se cierre. ?

Tengo un pequeño problema con el codigo, y es que el StringBetween no me da el valor que necesito o.o

Código: Seleccionar todo

	ShellExecute("C:\WINDOWS\System32\cmd.exe")
	WinWait("C:\WINDOWS\System32\cmd.exe")
	Send('find /I /N "' & $ReadIDP & '" "' & $Directorio & $array[$i] & '" >> C:\string.txt')
	Send("{Enter}")
	Sleep(5000)
	$Fopen = FileOpen("C:\string.txt")
	$ReadLine = FileReadLine($Fopen,3)
	$ValToWrite = _StringBetween($ReadLine,'id="','"')
	Msgbox(0,"",$ValToWrite)

#comments-start
	_FileWriteToLine($PathDir,$b,'<item id="1">',0)
	$b = $b + 1
	_FileWriteToLine($PathDir,$b,'<production id="' & $ValToWrite & '" count="' & $Count1 & '"/>',0)
	$b = $b + 1
	_FileWriteToLine($PathDir,$b,'<ingredient id="' & $ItemIC  & '" count="' & $Count2 & '"/>',0)
	$b = $b + 1
	_FileWriteToLine($PathDir,$b,'</item>',0)
	$b = $b + 1
#Comments-end

	Sleep(2000)
	Send('del C:\string.txt')
	Send("{Enter}")
Alguno ve por qué?
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Métodos para contar las líneas de un archivo.

Mensaje por Ximorro »

Lo de ejecutar el shell lo puedes hacer usando el parámetro /c de cmd.exe para ejecutar una línea de código. Además puedes usar la macro @ComSpec para que AutoIT te diga dónde está el intérprete de comandos, así vale para todos los Windows:

Código: Seleccionar todo

$cmd = @ComSpec & ' /c find /I /N "' & $ReadIDP & '" "' & $Directorio & $array[$i] & '" >> c:\string.txt'
RunWait($cmd, @TempDir, @SW_HIDE)
De esta manera no sale ninguna ventana y cuando el comando finaliza se el shell se cierra solo.
Le he puesto la carpeta de trabajo en el temporal aunque en este caso no hace falta, pero así ves cómo se hace. Con @SW_HIDE hacemos que la ventana shell no se vea.

Respecto a lo otro varias cosas...
Primero, al finalizar con el archivo abierto con FileOpen deberías usar FileClose para cerrarlo. De hecho lo borras mientras AutoIt aún lo tiene abierto, lo que no es bueno.
Lo más importante que te está fallando es que _StringBetween devuelve un vector, pues te da todos los resultados que encuentra, con lo que tienes que usar $ValToWrite[0] para tomar el primero.
Además antes de eso deberías asegurarte que ha encontrado algo, de lo contrario acceder al vector dará error, para eso se comprueba la macro @error

Esto último es una tontería, pero para ahorrar algo de proceso puedes omitir el parámetro /N de Find. Ahora lo puedes usar para depurar y ver dónde te está encontrando las cosas, pero para el programa final como es un dato que no se usa es tontería que Find lo escriba y que se lo pases a _StringBetween.
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
Haseo
Mensajes: 15
Registrado: 07 Ago 2011, 08:45

Re: Métodos para contar las líneas de un archivo.

Mensaje por Haseo »

Vale, fallo tonto.
Qué tal lo ves así?

Código: Seleccionar todo

$cmd = @ComSpec & ' /c find /I "' & $ReadIDP & '" "' & $Directorio & $array[$i] & '" >> c:\string.txt'
RunWait($cmd, @TempDir, @SW_HIDE)
	$Fopen = FileOpen("C:\string.txt")
	$ReadLine = FileReadLine($Fopen,3)
	$ValToWrite = _StringBetween($ReadLine,'id="','"')

	_FileWriteToLine($PathDir,$b,'<item id="1">',0)
	$b = $b + 1
	_FileWriteToLine($PathDir,$b,'<production id="' & $ValToWrite[0] & '" count="' & $Count1 & '"/>',0)
	$b = $b + 1
	_FileWriteToLine($PathDir,$b,'<ingredient id="' & $ItemIC  & '" count="' & $Count2 & '"/>',0)
	$b = $b + 1
	_FileWriteToLine($PathDir,$b,'</item>',0)
	$b = $b + 1
FileClose($Fopen)
$cmd = @ComSpec & ' /c del c:\string.txt'
RunWait($cmd, @TempDir, @SW_HIDE)
PD: Al principio me iba bien, pero ahora, sin tocar nada me salta este error:

Código: Seleccionar todo

C:\L2URIA Price Manager\Precios L2Uria.au3 (317) : ==> Subscript used with non-Array variable.:
$id = $ValToWrite[0]
$id = $ValToWrite^ ERROR
( Con o sin meter la variable $valToWrite dentro de la variable $id. Eso no es. )
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Métodos para contar las líneas de un archivo.

Mensaje por Ximorro »

Ya te lo he dicho antes, tienes que comprobar que _StringBetween no devuelva error. Hay que mirar la macro @error, si vale true es que no ha encontrado la cadena.

Alguna sugerencia:
Para borrar el archivo es mejor usar el comando nativo AutoIt FileDelete, será mucho más rápido al no tener que abrir un shell.

$b = $b + 1
es equivalente a
$b += 1
así es más corto. :smt003

De todas maneras me parece que escribir con _FileWriteToLine debe ser lentísimo, pues cada vez irá a buscar la línea concreta. Si simplemente estás escribiendo una línea detrás de otra usa simplemente FileWrite (o FileWriteLine para que te ponga los retornos de carro automáticamente). Son básicas de AutoIT (no necesitan udf) y será pero que mucho más rápido. Y encima no tendrás que seguir la cuenta de línea con la variable $b, pues cada línea que escribes se añade al final del archivo y ya está.

Estoy sospechando que para leer los archivos usarías algo parecido, que por cierto no nos has mostrado el código, porque el ejecutable no sirve para eso...
Bueno, está en el primer post la versión inicial pero no nos has puesto la versión con los bucles arreglados y tal, o es que me he liado...
Si usabas FileReadLine indicando la línea que tenía que leer era una mala idea, porque entonces cada lectura ¡¡volvía a leer el archivo entero hasta esa línea!!
En el primer post usas eso y supongo que la última versión seguía haciéndolo.
Si es eso, reprográmalo con un típico FileRead sin especificar número de línea, para que vaya una a una, vas a flipar de lo rápido que va. A lo mejor no te hace falta el truco del FIND.

Mira el programa que ha puesto Chefito hace poco para buscar en archivos, haz una búsqueda de texto y verás que va bastante rápido...
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Métodos para contar las líneas de un archivo.

Mensaje por Ximorro »

He hecho la prueba de leer tu primer archivo, 00000-00099.txt, con FileRead poniendo número de línea o no. Resultados:
Con número de línea: 2.122 segs
Sin número de línea: 0.014 segs
En cada ordenador los números cambiarán, pero el rendimiento será siempre proporcional.

Especificando número de línea ¡es 150 veces más lento! Así que cambia el sistema y verás que va mucho mejor. Probablemente no necesites abrir shells y crear archivos temporales, haciéndolo todo en AutoIT creo que irá aceptablemente bien.
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Métodos para contar las líneas de un archivo.

Mensaje por Ximorro »

Haseo, como decías que era muy lento me ha picado el tema del rendimiento y por curiosidad he seguido investigando.

Primero he comparado la búsqueda con ReadLine poniendo número de línea o no, buscando en TODOS los archivos.
Si no pones número de línea se los lee todos en... ¡2 segundos!, si la pones ya son ¡nada menos que 7 minutos y 37 segundos! Sin comentarios.
Así que sólo con ese cambio ya te irá muchísimo más rápido.

Quedándome con la versión rápida, he hecho la comparativa de buscar el item con el comando Find del shell, o "a mano" en AutoIT leyendo cada archivo línea a línea y buscar dentro el item.
Pues bien, buscar un elemento que está en el archivo que está a mitad de la lista, y que además el item está en mitad de ese archivo (o sea, la búsqueda media, se trata de name="Diadem") me da que con Find me tarda 13.97 segs, y leyendo desde AutoIT... ¡sólo 1.3 segs!

Buscando el último elemento, para que se lo lea todo, el caso más costoso (en realidad ha tenido que ser name="Rabbit Ear", porque el último está repetido en nombre en varios archivos...), me sale con Find en 30.8 segs, y con el otro sistema ¡3.2 segs!

Así que te recomiendo que lo hagas desde puro AutoIT, es mucho más rápido.
Ah, he tomado tiempos después de ejecutar cada algoritmo varias veces, para que quedaran los TXT en caché y no afecte la lectura de disco de forma diferente a cada método.

Lógicamente lo tengo hecho, pero como ya lo tienes bastante avanzado en vez de pasártelo creo que es mejor que lo hagas tú y así aprendes mucho más. Por supuesto sigue preguntando las dudas que salgan. Te digo las cosas que me he encontrado por si te ayuda:

No he usado ninguna UDF, con las funciones base de AutoIT he tenido bastante, y son más rápidas.

Por ejemplo no he usado _FileListToArray, sino que recorro los archivos usando FileFindFirstFile y FileFindNextFile, mira la ayuda de cualquiera de ellos y simplemente copiando el ejemplo que viene, con pocas modificaciones lo tienes.

Para buscar el item, la alternativa rápida a FIND, es ir leyendo cada archivo con FileReadLine pero sin especificar número de línea. En cada línea busco a ver si está el item con StringInStr, y si está es cuando se extrae el ID.

Por supuesto cuando encuentro un item dejo de mirar archivos, se abortan los bucles (cerrando archivos abiertos) y se da la solución.

El núcleo del asunto es un doble bucle, un While externo que va recorriendo los archivos, y otro While interno que va leyendo las líneas de cada archivo. Y todo eso está en apenas 15 líneas ¡de verdad!

Venga, a ver si te sale, ya ves que puede ser super-rápido, y además sin necesidad de recurrir a herramientas externas (mecanismo muy útil que conviene conocer, pero en este caso no hace falta porque además es 10 veces más lento).

Ah, por cierto, si después de todo te empeñas en hacerlo con Find, ten en cuenta que en la línea de comandos del DOS, si quieres buscar las comillas tienes que doblarlas, por ejemplo hay que buscar
FIND /C /I "name=""Rabbit Ear""" nomarchivo.txt
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
Haseo
Mensajes: 15
Registrado: 07 Ago 2011, 08:45

Re: Métodos para contar las líneas de un archivo.

Mensaje por Haseo »

Uhm... A mi con Find no me tarda tanto... es decir, para encontrar por ejemplo Mamba edge, me tarda muchísimo menos de un segundo. Pero seguiré tu consejo, ya que quiero aprender, hare una copia del archivo y empezaré de cero lo que son las funciones y demás.

Una pequeña duda, que seguro que será muy, muy de novato:

Muchas veces tengo que usar variables en distintas funciones, y claro, si la variable la tengo definida en otra función, o directamente fuera de ella, me dice que es posible que haya usado la variable $x antes de definirla. Eso segun creo se arregla si yo defino las variables como Global, Local, o Dim. Pero he leido la definicion de las 3, y no termino de entender cual me vendría mejor en algunos casos. De momento voy tirando con Global...

como ves esto de momento Ximorro? es lo que tengo hasta ahora...

Código: Seleccionar todo

			; Shows the filenames of all files in the current directory.
			$search = FileFindFirstFile($Directorio & "*.*")
			$asdf = FileFindNextFile($search)

			$Fopen = FileOpen($Directorio & $asdf)
			If $Fopen = -1 Then
				MsgBox(0, "Error", "Unable to open file.")
				Exit
			EndIf
			$FileRead = FileRead($Fopen)
			If $FileRead = 1	Then
				MsgBox(0,"","file not opened in read mode or other error.")
				Elseif $FileRead = -1	Then
				MsgBox(0,"","end-of-file is reached.")
			EndIf
			$Resultado = StringInStr($FileRead,$ValID)

			If $Resultado = 1	Then
				MsgBox(0,"","Invalid 'start' or 'occurence' parameter given.")
				Elseif $Resultado = 0	Then
				MsgBox(0,"","Substring not found.")
			EndIf

			; Check if the search was successful
			If $search = -1 Then
				MsgBox(0, "Error", "No se han encontrado archivos/directorios.")
				Exit
			EndIf

;			While 1

;				If $Resultado >= 2	Then
					MsgBox(0,"",$valID & @CRLF & $Resultado)
;					ExitLoop
;				EndIf

;			WEnd

			; Close the search handle
			FileClose($search)
Ya ves que es el mismo ejemplo de autoit, un poco retocadito... Uhm, la ultima parte no está lista aun, estoy haciendo pruebas, y FileReadLine si no especifico la linea a buscar, me salta que no encuentra resultados, porque busca mi stringinstr en la primera linea del archivo, asi que imagino que te referias a FileRead. El cual tampoco devuelve la línea, si no el numero de caracteres que hay hasta el resultado que encima, me sale que la Short sword está en el puesto 63 del archivo, y está en el 61... Me guias un poco?
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Métodos para contar las líneas de un archivo.

Mensaje por Ximorro »

¡Menos de un segundo! ¡A mí me tarda 23!
¿Qué cadena buscas exactamente? ¿'name=""Mamba Edge""', directamente 'Mamba Edge'? Está claro que en cada ordenador costará una cosa, y éste es un pobre XP a 2GHz con un disco no muy rápido, pero la diferencia es bárbara.
Claro que la comparación hay que hacerla con los dos programas en el mismo sistema, a mí esos 23 segundos se me reducen a 2.7 con el método sin Find.

Tengo que decir que busco en los archivos ordenados alfabéticamente, sería interesante saber en cuántos has buscado antes de encontrar el Melba Edge, porque igual si los tienes ordenados de otra manera resulta que es de los primeros en buscar. A mí cuando encuentra 15500-15599.txt con el resultado, ya ha buscado antes en 155 archivos, vaya, casi todos ;-)

Sería interesante que nos pasaras un código funcional para que probemos. Funcional es que se pueda ejecutar, para reducirlo sin ponerle GUI le puedes poner a mano los valores de las variables de la carpeta de archivos y el texto de búsqueda.

Respecto a ese error que comentas es típico de usar una variable que aún no tiene ningún valor. Por ejemplo si haces:
$a = $b + 2
y $b aún no vale nada, pues te da un error porque no sabe qué tiene que sumar.

Efectivamente para usar una variable en diferentes funciones la tienes que declarar como Global. Para eso declárala FUERA de cualquier función, en el programa principal. Las variables locales (con Local) se declaran DENTRO de una función, y sólo son visibles en esa función. NO uses DIM, está ahí por razones históricas y los desarrolladores desaconsejan su uso.

Sí, has retocado el ejemplo, pero has quitado el bucle, que es lo más importante. El bucle es lo que pasa de archivo a archivo, así que te quedas en el primero. De la misma manera te falta otro bucle que lea todas las líneas del archivo (o hasta que encuentre el item).
Al cambiar FileReadLine por FileRead lo que haces es leer el archivo entero, al no leerlo por líneas no sabes cuál es. Sí que es con FileReadLine pero con un bucle que vaya leyendo las líneas. Es más, si miras la ayuda de FileReadLine precisamente el ejemplo lee un archivo entero línea a línea. Como ves hay un bucle que las recorre, ¡no lo quites!

Es difícil probar un código a mitad. Si es posible pásanos códigos que se puedan ejecutar. Por ejemplo sería interesante saber qué forma tienen las variables $Directorio y $valID. Creo que $Directorio tiene la barra final de directorio, $valID no sé cómo será, y sería interesante hacer lo mismo que tú para que nos pasen las mismas cosas en la pruebas. (No es lo mismo buscar 'Mamba Edge' que 'name="Mamba Edge"', por ejemplo).

Venga mira lo de los bucles y nos dices. Algunas sugerencias y correcciones:
.- ¿Por qué no buscas con FileFindFirstFile sólo los archivos de texto "*.txt"? Por asegurarse.

.- Después de FileFindFirstFile es buena idea mirar si hay archivos, tal como hace en el ejemplo. Ah, veo que lo haces luego... ¡pero hay que hacerlo antes de trabajar con los archivos! Esa condición del If $search = -1 hay que ponerla justo después del FileFindFirstFile, sino no tiene sentido.

.- Estás mirando mal los códigos de error de StringInStr . Los errores los suelen devolver las funciones en la macro @error, no en el valor que devuelven (aunque si hay error a veces retornan valores especiales). Así por ejemplo es cierto que StringInStr devuelve 0 si no encuentra la cadena (pero eso no es exactamente un error, pues el proceso se ha ejecutado correctamente). Pero el error -1="Invalid 'start' or 'occurence' parameter given." se comprueba mirando @error:

Código: Seleccionar todo

If @error = 1 Then
	MsgBox(0,"","Invalid 'start' or 'occurence' parameter given.")
Elseif $Resultado = 0 Then
	MsgBox(0,"","Substring not found.")
EndIf
La comprobación de FileOpen la tienes bien, ahí devuelve el error en el retorno de la función. Esto demuestra que hay que mirar bien la documentación de las funciones, para ver cómo trabajan y cómo devuelven los errores, porque cada uno lo hace de una manera (pero atento al mecanismo de @error, en AutoIt se usa mucho)

.- Cuando abras un archivo, ciérralo cuando termines de trabajar con él. Es decir, como tienes un FileOpen($Directorio & $asdf), debería haber un FileClose($Directorio & $asdf) cuando termines de trabajar con él.

.- Esto último ya es cuestión de gustos pero yo no pondría a variables el mismo nombre que las funciones (como haces con FileRead), puede ser un lío, por ejemplo si te da un error con FileRead puede ser un poco lioso saber si se está refiriendo a la función o a la variable.


Ah, pásanos el código que busca con Find, quiero probarlo en mi ordenador a ver si me va más rápido que el mío.
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
Avatar de Usuario
Chefito
Profesional del Autoit
Mensajes: 2035
Registrado: 21 Feb 2008, 18:42
Ubicación: Albacete/Cuenca (España)

Re: Métodos para contar las líneas de un archivo.

Mensaje por Chefito »

Haber, haz lo que te dice Ximorro. Si practicamente es coger los ejemplos de la ayuda de las funciones filefindfirtsfile y readfile, mezclarlos y variarlos muy muy poquito para adaptarlo a tu código :smt002 .
El problema no está en encontrar el texto. Eso sabemos que es muy rápido con stringinstr. El problema es ganar velocidad contando líneas, para saber en que línea está ese texto. Si me hubieses hecho caso, hubieses encontrado un código que lo hace bastante rápido (por supuesto según coincidencias). A mí me ha tardado buscando la cadena 'Mamba Edge' y devolviendote el número de línea donde se encuentra, en un p4 a 1600 con 768 mb de ram y xp sp3 20,3 segundos (con antivirus y antiespias activo). He reiniciado el ordenador y lo he vuelto a ejecutar desactivando el antiespias y el antivirus y me ha tardado 9,46 segundos. Se nota que este ordenador es lentito :smt005 .

Luego lo he probado en mi portatil y el resultado es de una velocidad de 4,49 segundos (por supuesto sin desactivar el antiespia ni el antivirus :smt005 ). El portatil es bastante nuevo, procesador amd athlon II p320 dual-core (2,1 ghz), 4 gb ddr3, w7 home 64bits.

Resultado de la búsqueda en consola del Scite (la 2º vez que ejecuté):
>Running:(3.3.6.1):C:\Program Files (x86)\AutoIt3\autoit3_x64.exe "C:\Users\Manuel\Desktop\L2URIA's Multisell Generator\items\Nuevo AutoIt v3 Script.au3"
15500-15599.txt, línea: 547
15800-15899.txt, línea: 1730
15900-15999.txt, línea: 475
16100-16199.txt, línea: 1064
+>12:45:22 AutoIT3.exe ended.rc:0
>Exit code: 0 Time: 4.045
Método que he utilizado: El último que te dije, el de hacer una función que te contase los saltos de líneas en los ficheros que encontrase coincidencia con el texto :smt002 . Me ha sorprendido lo rápido que es. No me imaginaba esa velocidad :smt003 . Por cierto, muy facil de implementar.
Intenta hacerlo.

Saludos.
Cita vista en algún lugar de la red: En este mundo hay 10 tipos de personas, los que saben binario y los que no ;).
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Métodos para contar las líneas de un archivo.

Mensaje por Ximorro »

Esta es otra opción (que sería más parecido a lo que tienes por ahora, Haseo), se trata de leer el archivo entero con FileRead, mirar si está la cadena, y si está entonces se vuelve a mirar contando los retornos de carro.
No sé si compensará el hecho de leer el archivo resultado dos veces (la primera entero y luego contando líneas), quizás así sea peor cuando se encuentra pronto la cadena y mejor cuando tiene que leer muchos archivos.

¡Menuda diferencia con y sin antivirus!

Chefito, te paso por MP mi rutina que en vez de leer todo el archivo va siempre línea a línea, para que me digas cómo te va de rápido, tengo curiosidad.
Eso sí, yo cuando encuentro una coincidencia doy ese resultado y salgo, al principio no sabía que para un item podía haber varias entradas, si se quieren todas habría que completarlo para que funcione como el tuyo (en vez de abortar bucles seguir buscando en todos los archivos)
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Métodos para contar las líneas de un archivo.

Mensaje por Ximorro »

Haseo, Chefito me ha indicado algo que se nos ha pasado: que FIND puede buscar en varios archivos a la vez, se le puede pasar todos los txt y en el archivo de salida saca todo lo que encuentra.
Lógicamente eso es mucho más rápido que hacer un Find en cada archivo.
En mi ordenador buscar en cada archivo (y no parando cuando encuentra el item, sino que sigue mirando a ver si hay más coincidencias) me tarda algo más de 30segs. ¡Con su método son 6segs!. Analizar el resultado es más complejo pero desde luego vale la pena.
Lo que no entiendo es cómo a ti te cuesta menos de un segundo usando FIND, ¿miras en todos los arhivos? Si es así ESE es el método.

En cualquier caso a nosotros nos siguen yendo mejor los métodos con todo en AutoIT, sin FIND.
Mi método es más lento, pero quizás más fácil de programar, más que nada porque básicamente es juntar los ejemplos de la ayuda para FileFindFirstFile y FileReadLine, así que yo intentaría eso primero.

El método de Chefito es casi tres veces más rápido (en mi ordenador se lo mira todo en poco más de un segundo), leyendo el archivo completamente en memoria (no línea a línea), y sólo si se encuentra el nombre del item, se cuentan las líneas.

De todas maneras creo que o no nos has expresado bien realmente el objetivo o yo no lo he cogido del todo. Porque realmente a ti te da igual en qué número de línea está el item, tú lo que quieres es obtener el ID de ese item ¿no?
Si es eso será mejor que te centres en el objetivo real para hacer el código más óptimo. Si te rompes los cuernos para saber en qué número de línea está el item y luego lo que quieres es realmente otra cosa...

Por cierto, que no te ponemos los códigos porque no te falta mucho para conseguirlo, creo que te falta un poco entender un poco lo del WHILE en esos ejemplos de la ayuda, cuando tengas eso será fácil.
Cuando tengas tu solución si quieres ya te pasamos las nuestras y comparas o haces remezcla o lo que quieras.

Y por supuesto sigue preguntando dudas que aquí estamos.
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
Haseo
Mensajes: 15
Registrado: 07 Ago 2011, 08:45

Re: Métodos para contar las líneas de un archivo.

Mensaje por Haseo »

Al parecer no me entendiste. Mi método era leer todos los archivos con FileRead, que es más rapido que ir linea por linea. Y entonces, al encontrar el archivo que contiene "X" string, lo lleva a la funcion del Find, el cual solamente busca en el archivo que previamente autoit encontró con resultados.
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Métodos para contar las líneas de un archivo.

Mensaje por Ximorro »

Ah, de acuerdo, de todas maneras ya podías habernos enseñado el código.

Pues si ya estás satisfecho con esa solución adelante. Si quieres probar otras opciones nos lo dices.
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
Responder