Curso Básico de Programación
en Visual Basic

Entrega Trece: 10/Feb/98
por Guillermo "guille" Som

Si necesitas ver cualquiera de las entregas anteriores, aquí tienes los links:
La Primera, la Segunda, la Tercera, la Cuarta, la Quinta, la Quinta++, la Sexta, la Séptima, la Octava, la Novena, la Décima, la Undécima, la Doce

 

Desde luego que los días pasan como horas... no sé si será la edad, pero... ¡Jo! Cuando he visto la fecha de la entrega anterior... ¡¡¡ Hace un mes !!!
No voy a prometerte nada, pero haré un pequeño esfuerzo para acelerar los plazos de entrega, sino, puede que te aburras o decidas cambiar de profe...
La solución sería: disponer de un portátil... pero... en fin... Esto de la esponsorización no da para tanto... lo mismo a ti te sobra uno... ejem!

Bueno, después de la "necesaria" introducción, vamos a lo que te ha traído por aquí; ya que me imagino que no es precisamente el saber que "necesito" un portátil... esto... si es un Pentium 200, con un mínimo de 32 megas de RAM, pantalla SVGA color, disco duro de un par de Gigas y modem... pues mejor... je, je, nunca se sabe si te puedes encontrar con un alma caritativa... y, como dice el refrán: "El que no llora... no mama..." ;-)

¡Guille! ¡Déjate de chorradas y vamos al tema! (esta es la voz de mi conciencia: mi otro yo)

En la entrega anterior ya vimos cómo guardar y recuperar información de un fichero; vamos a seguir con el tipo secuencial, pero esta vez vamos a leer todo el contenido de una sola vez, para ello vamos a usar dos nuevas funciones: LOF e INPUT.

No te confundas con la función INPUT, ahora verás que no se usa de igual forma de como usamos anteriormente la "instrucción", recuerda que esta nueva, es una función y las funciones siempre devuelven un valor. La que antes usamos era una instrucción y las instrucciones hacen algo, pero no devuelven valores... ya verás que esto mismo se puede aplicar a las funciones; ya que estamos en ello, y a título de curiosidad, si no quieres usar el valor devuelto por una función, cosa que se hace muchas veces con las llamadas al API de Windows, deberás hacerlo anteponiéndole a la función la instrucción CALL. Esto lo veremos cuando empecemos con el API, que, aunque te parezca que es un tema avanzado, lo empezaremos a ver muy pronto.

Ahora veamos cómo usar esas dos funciones:
variable = LOF(#canal)
Esta función devuelve, en bytes, el tamaño del fichero abierto con el canal indicado dentro del paréntesis.
LOF es la abreviatura de: Length Of File (longitud del fichero).
Por tanto si queremos saber la longitud de un fichero, lo abrimos, asignamos a una variable el valor devuelto por LOF y después hacemos lo que tengamos que hacer... Que sólo quieres averiguar la longitud, pues lo cierras y ya está, por ejemplo:

Dim nFic As Integer
Dim sFic As String
Dim tamFic As Long

sFic = "C:\Autoexec.bat"

nFic = Freefile
Open sFic For Input As nFic
tamFic = LOF(nFic)
Close nFic

MsgBox "El tamaño de " & sFic & vbCrLf & "es de " & tamFic & " bytes"

La verdad es que si lo que pretendes es saber la longitud de un fichero, puedes usar la función FileLen, ésta se usa poniendo el nombre del fichero entre los paréntesis y también devuelve el tamaño en bytes:
(Tanto una función como la otra devuelven un valor LONG)

Dim sFic As String

sFic = InputBox("Nombre del fichero:", "Mostrar tamaño", "C:\Autoexec.bat")
If Len(sFic) Then
    MsgBox "El tamaño de " & sFic & vbCrLf & "es de " & FileLen(sFic) & " bytes"
End If

Este trozo de código te preguntará, (usando InputBox), el nombre de un fichero, por defecto te mostrará C:\Autoexec.bat y si se ha escrito algo, mostrará el tamaño en bytes.
Fíjate que el valor devuelto por una función no sólo se puede asignar a una variable, sino que también se puede usar directamente. Si, ya sé que lo he dicho en otras ocasiones, pero lo repito para que no te quede duda.

Ahora veamos cómo "funciona" la función INPUT:
Esta función devuelve una cadena con el contenido de un fichero que esté abierto... realmente devuelve el número de caracteres que le indiquemos y esos caracteres los tomará del fichero abierto con el "canal" indicado, veamos cómo usarla:

cadena = Input$(numCar, #canal)

El signo dólar ($), lo uso para saber que estoy trabajando con una función que devuelve un valor de cadena...
La mayoría de este tipo de funciones del Visual Basic, devuelven indistintamente un valor variant o string, para obligarle a que devuelva una cadena, debemos ponerle al final el signo $, ni que decir tiene que esto sólo es válido para las funciones que devuelvan cadenas de caracteres, no para las que devuelvan otro tipo de datos... Pero no te preocupes de este tema, ya que el VB se encarga de hacer lo que tenga que hacer para que obtengas lo que tienes que obtener... ¡¡¡Que lío!!!

Ahora vamos a ver cómo podemos leer todo el contenido de un fichero y asignarlo en una variable de cadena:

Dim nFic As Integer
Dim sFic As String
Dim tamFic As Long
Dim sContenido As String

sFic = InputBox("Nombre del fichero:", "Mostrar fichero", "C:\Autoexec.bat")
If Len(Dir$(sFic)) Then
    nFic = FreeFile
    Open sFic For Input As nFic
    tamFic = LOF(nFic)
    sContenido = Input$(tamFic, nFic)
    Close nFic
    MsgBox sContenido
End If

Fíjate que uso un MsgBox para mostrarlo, en caso de que el contenido del fichero sea "demasiado" grande, el botón Aceptar no se verá... tienes dos opciones: pulsar Intro o ESC, de esta forma quitarás el mensaje de la pantalla, a pesar de que no tenga "visible" el botón Aceptar.

Un par de detalles, la función Input$() devuelve una cadena de caracteres, el tamaño máximo de caracteres que admite estará delimitado por el sistema operativo y sobre todo por la versión del VB, en 32 bits este tamaño "casi" no tiene límite, pero en 16 bits, será de 64 KB como máximo.
El otro detalle es que la comprobación que se hace para saber si existe el fichero, no es a prueba de "manazas". Me explico: si el nombre que se indica en sFic no existe y/o el path indicado tampoco, no pasa nada, todo funcionará bien; pero si le indicas la unidad A, o cualquier otra, cuando no hay disco insertado, la cosa deja de funcionar y te mostrará un error.

Pero todo esto tiene solución, ahora mismo te diré cual es, pero antes voy a desglosarte el funcionamiento de Len(Dir$(...))
Fíjate que aquí se usan dos funciones:

Len(Cadena)   Esta función devuelve el número de caracteres de la cadena indicada
Dir$(sFichero)   Esta otra, lo que devuelve es el nombre del primer fichero que coincida con la "especificación" indicada en sFichero, en caso de que no haya coincidencias, devolverá una cadena vacía.

Por tanto, si no existe el fichero, Dir$ devuelve una cadena vacía y la longitud de una cadena vacía es CERO, así que en la comparación, If Len(Dir$(sFic)) Then Visual Basic sustituirá Len(Dir$(sFic)) por el valor devuelto, recuerda que para IF un cero significa FALSO y cualquier otro valor será VERDADERO, insisto en este punto, ya explicado anteriormente, para que se te quede claro.

Lo que quizás no sepas es que en Dir$(sFic), sFic puede contener signos comodines (? y/o *), para indicar cualquier tipo de fichero. Esto se suele usar también en las rutinas de búsqueda que se hacen en las bases de datos, así que mejor que te vayas enterando cómo usarlo y "buscar" por ahí información, ya que aquí te voy a explicar un poco el significado, para que lo puedas usar al indicar los ficheros.
Como "añadido", decirte que en el sistema de búsqueda del Windows 95, también puedes buscar ficheros o contenidos, usando estos comodines.

Ejemplos: (las pruebas se pueden hacer desde una ventana del MS-DOS, usando el comando DIR)

  La interrogación (?) se usa para indicar que no nos importa el carácter que haya en esa posición.
  El asterisco (*) sirve para que nos devuelva todos los que tengan los caracteres anteriores a este signo, pero que los restantes no los tenga en cuenta.

 

Dir Auto*.bat   Mostrará todos los ficheros que empiecen por Auto y que la extensión sea .bat
Dir Auto*
o
Dir Auto*.*
  Todos los ficheros que empiecen por Auto, sin importar ni la extensión ni nada, ya que al usar .* se indica que cualquier cosa es válida.
Es recomendable usar la segunda forma.
Dir A?t*.*   Mostrará todos los ficheros que la primera letra sea A y la tercera T, como se usan *, esto indica que nos da igual lo que haya después de la T, por tanto si tuviésemos ficheros llamados: Arte.txt, Autoexec.bat, Automovil.doc, Arial.ttf, nos devolvería los tres primeros, porque coinciden en lo indicado.
Dir Dato??98.txt   Nos devolverá todos los ficheros que tengan en las 4 primeras letras la palabra dato y en las posiciones 7 y 8 el número 98, la extensión será txt. Además en las posiciones 5 y 6 podrá tener cualquier cosa, pero deberá tener 8 caracteres.
Así que Dato0198.txt, dato1298.txt sería nombre encontrados, pero no lo sería: data0198.txt ni dato0298.doc, en el primer caso, porque empieza con la palabra data y en el segundo porque la extensión no es txt

Una vez visto, por encima, esto de los signos comodines, vamos a ver cómo hacer nuestra forma de comprobar si existe un ficheros, algo más fiable y segura.
Para ello, vamos a crear una función que se llame: Existe y esta función devolverá FALSO (cero) si el fichero no existe y en caso de que exista, devolverá VERDADERO (-1)
Esta función podremos usarla de cualquiera de estas dos formas:

If Existe(unFichero) Then
    'Si existe, hacer lo que corresponda
End If

If Not Existe(unFichero) Then
    'El fichero en cuestión no existe
End If

Para poder "detectar", o interceptar, los posibles errores que se produzcan al intentar comprobar si existe el fichero, usaremos esto:
On [Local] Error Resume Next
Con estas instrucciones, se le indica al Visual Basic que en caso de que se produzca un error, "pase" de ese error y continúe con la siguiente instrucción.

Esto está bien, pero... ¿cómo sabremos que se ha producido el error? ya que, si continua... pues... eso, no se detiene...
Respuesta: Usando la función ERR.

Esta función devuelve el número del error que se haya producido, o cero si no se produjo error.
A partir del VB4, esta función se puede sustituir por la propiedad Number del objeto Err, por tanto Err.Number también nos dirá que número de error se ha producido, ten en cuenta que Number es la propiedad por defecto de este objeto.
Pero como quiero que este curso básico sea lo más genérico posible y no se incline sólo por el VB4 o superior... pues intentaré usar funciones que sean compatibles... aunque tampoco prometo nada, así que te recomiendo que dejes de lado las versiones de 16 bits o al menos la versión 3 del VB, porque esta "consideración" que estoy teniendo puede que cambie... de hecho seguramente pondré cosas que sólo estarán disponibles a partir de la versión 4... y cuando la cosa vaya avanzando más, incluso sólo cosas de la versión 5... aunque para esas fechas ya estará en el mercado el VB7, por lo menos...

El caso es que yo estoy acostumbrado a usar ERR, así que... eso es lo que hay... je, je.

Y ya sin más rodeos, veamos cómo quedaría la función Existe, si te fijas es casi igual que la que puse hace ya algunas entregas, pero usando la detección de errores:

Private Function Existe(ByVal unFichero As String) As Boolean
    On Local Error Resume Next

    Existe = Len(Dir$(unFichero))
    If Err Then
        Existe = False
    End If
    Err = 0
    On Local Error GoTo 0
End Function

Te explico cada una de las líneas:

Private Function Existe(ByVal unFichero As String) As Boolean

Esta es la declaración de la función, el Private es por si lo quieres usar en un form, o en cualquier otro módulo, pero que sólo sea visible para el código de ese módulo.
Si quieres que esté visible en todo el proyecto, cosa recomendable para este tipo de funciones, cambia el Private por Public y escribe el código en un módulo BAS. Así podrás usarlo en cualquier form o módulo que tengas en tu proyecto.

Veamos porqué he declarado el parámetro de esta forma: Byval unFichero As String
Este es el parámetro que le pasamos a la función, es decir: el fichero o especificación que queremos comprobar si existe. Lo de especificación es porque puedes usar esta función para saber si existen archivos que empiecen por la A, asignando al parámetro los comodines que creas necesarios: If Existe("C:\A*.*") Then comprobará si en el directorio raiz de la unidad C hay archivos que empiecen por la letra A.

El ByVal le indica al Visual que use una copia del parámetro, con lo cual evitaremos que el código de nuestra función lo modifique; ya que al usar una copia, no tenemos acceso al original, esto también acelera el manejo de nuestra función.

El As Boolean del final, es el tipo de dato que devolverá nuestra función, también se podría usar Integer, de esta forma, si estás usando el VB3, podrás usar la función, sin mayor problema.

On Local Error Resume Next

Esta es la instrucción que pone en marcha la detección de errores.
Local es para indicarle al VB que sólo esté operativa dentro de esta función, sirve para que, en caso de que externamente haya otro mecanismo de detección de errores, el que esté operativo sea el que acabamos de declarar... cuando abandonemos la función seguirá funcionando la otra rutina que hubiera.

Existe = Len(Dir$(unFichero))

Asigna a Existe la cantidad de caracteres devueltos por la función DIR. Al ser del tipo Boolean, el VB automáticamente asigna Verdadero o Falso.
En el caso de que la función se haya declarado como Integer, un cero indica que es falso y cualquier otro valor que es verdadero, por tanto la cosa funcionará igualmente independientemente del tipo devuelto por esta función.
¿Seguro?
Veamos un ejemplo:

If Not Existe("algo.txt") Then
    MsgBox "El fichero indicado no existe"
End If

Prueba esto cambiando el tipo de dato devuelto por la función Existe, cuando lo pongas como Integer, siempre te dirá que no existe el fichero...
La explicación de porqué ocurre esto, ya lo vimos anteriormente, y es porque NOT Un_Número, devuelve un número, no un cero... Y recuerda que, cuando Existe es del tipo Integer, devuelve el número de caracteres...

Si quieres que sólo devuelva 0 ó -1 para que sea igual que False/True, podrías hacer esto otro:
Existe = Len(Dir$(unFichero)) <> 0
De esta forma se evalua la expresión y en caso de que sea cierto que el resultado es distinto de cero, se asignará un -1, en cualquier otro caso se asignará un cero y ahora si que actuará igual que si el tipo devuelto fuese boolean.

If Err Then

Ahora comprobamos si se produjo algún error al intentar buscar el fichero en cuestión.

En el supuesto de que se produzca un error, se pasará a la línea después del IF, asignando FALSE al valor que devolverá la función. Como sabrás o te habrás imaginado, el valor que debe devolver una función se asigna al nombre de la función, en otros lenguajes se usa RETURN valor, por ejemplo en C o en el JavaScript...
Por tanto, Existe = False, sólo se asignará cuando se produzca un error.

Err = 0

Esta es una de esas recomendaciones "obligatorias" que yo haría siempre que uses el Resume Next, en este caso no es necesario porque el código de la función termina ahí, pero si hubiese más código, ese valor de error seguiría asignado a Err y cualquier otra comparación posterior al objeto Err, podría "alterar" el buen funcionamiento de nuestro programa.
(Recuerda que en VB4 o posterior, realmente se asigna a la propiedad Number del objeto Err)

On Local Error Goto 0

Esta última línea "libera" la detección de errores de esta función, en nuestro caso, tampoco es necesaria, ya que al finalizar un procedimiento, cualquier rutina de detección de errores se elimina. Esto, al igual que lo dicho anteriormente, sirve si queremos dejar de detectar errores en las siguientes líneas de nuestra rutina. Como ya no hay más líneas de código, la verdad es que no es necesaria, pero suelo usarla siempre, costumbres que tiene uno de saber cuando dejo de interceptar los errores.

Bien, ya tenemos nuestra función a prueba de usuarios inexpertos o con malas intenciones... también para los olvidadizos...
¿Por qué me miras?
¿Es que nunca has intentado acceder a la unidad A cuando aún no has insertado un disquete?
Pues yo sí... je, je...

Vamos a probarla.

Crea un nuevo proyecto, agrega un módulo bas.
Asegúrate que tiene Option Explicit al principio, ya sabes que esto es para que cualquier error tipográfico al escribir una variable, no obligará al VB a crearla, sino que nos avisará de que esa variable no existe, es decir, sirve para obligarnos a declarar todas las variables que vayamos a usar.
Ahora copia y pega o escríbela nuevamente, la declaración de la función Existe, asegúrate que sea pública y no privada.

Cierra el módulo y asegúrate que el Form1 esté visible y en modo de diseño, es decir que se vea el Form. Añade un Label, un TextBox y un CommandButton.
Modifica el caption del label para que contenga este texto: Fichero a comprobar:
En el caption del botón escribe: Comprobar.
Sitúa los controles para que tengan un aspecto "agradable" y escribe lo siguiente en el Command1_Click:

Private Sub Command1_Click()
    If Existe(Text1.Text) Then
        MsgBox "Si existe el fichero: " & Text1.Text
    Else
        MsgBox "NO EXISTE el fichero: " & Text1.Text
    End If
End Sub

Prueba a escribir en el TextBox signos comodines para comprobar que todo funciona, por ejemplo: *.bas
Igualmente escribe algún nombre que sepas que no existe... y para salir de dudas, intenta acceder a un fichero de la unidad A, pero sin poner un disco...

Todo correcto, ¿verdad?
Pues me alegro, de que así sea...

No, no te preocupes que no hay "gato" encerrado... bueno, sí, los tres que tengo en mi casa, pero esos no tienen nada que ver con el programa...

No te voy a poner ningún ejercicio en esta entrega, ya lo haré en la siguiente, así que paciencia y no desesperes, que ya la tengo escrita en papel, por tanto puede que mañana mismo esté en línea... es que si continúo, se me va a pasar la hora y quiero que sea hoy día diez el día que publique esta entrega... chorradillas que se le ocurren a uno...

 

Como es habitual, y las buenas costumbres no hay que perderlas, si quieres hacer algún comentario sobre esta entrega o sobre el curso básico en general... o tienes ese portátil que me haría tan feliz... y me lo quieres regalar, claro, usa este link
Te repito por enésima vez que no aproveches el link para las consultas... que ya nos vamos conociendo... a pesar de que no des la cara...

Nos vemos.
Guillermo


 
entrega anterior ir al índice siguiente entrega

Ir al índice principal del Guille