[ Foro de Pascal ]

error en archivo

14-Jun-2011 12:51
oscar gomez
19 Respuestas

Cordial saludo,gracias profesor Nacho y Antonio.

he realizado como practica adicional al tema que estoy tratando de archivos y obtengo un error en la linea indicada:

datos.txt:

mario      3.5   3.9
jose       4.2   3.7
pedro      2.9   3.3
alicia     4.9   2.8
marta      4.3   4.1


EL CODIGO LO ADJUNTO Y EL ERROR LO ILUSTRO EN LA LINEA DONDE ME DA EL ERROR DE EJECUCION " ERROR 100: DISK READ ERROR" LO ENMARCO CON ****, OJALA PUEDAN ORIENTARME A HAYAR MI ERROR Y AGRADECERLES DE ANTEMANO SU AYUDA


14-Jun-2011 16:10
Antonio P.G.

Hola Óscar.

Lo primero, bonito programa.

El error es un despiste: el archivo que asignas es de tipo texto ".txt". Cuando un archivo es de "records", la extensión es ".dat".

Por lo tanto, tienes 2 opciones:

1. Hacer procedimiento llamado (por ejemplo) "LeerAlumno", y que lea un alumno del archivo. Este procedimiento utilizarlo en el procedimiento que denominas "CargarInfo".

2. Crear un procedimiento que escriba y guarde alumnos en un archivo de extensión ".dat" mediante el uso de "records". Ese archivo no será legible desde el bloc de notas, pero sí desde tu programa.

Por cierto, lo que quedaría ya genial para este programa es añadir un menú de tipo "repeat...until" en el cuerpo del programa principal y pedirle al usuario que introduzca la ruta hacia el archivo. De esta forma, podrías hacer varias operaciones de crear archivos para diferentes clases, visualizarlos, cambiar a otro archivo mediante la re-lectura de la ruta del archivo... (Ideas, nada más).

¡Ciao!


15-Jun-2011 12:52
oscar gomez

Antonio, hola gracias por tus comentarios, aun asi cambie la extension del archivo datos.txt por datos.dat pero aun asi perciste el mismo error al ejecutarlo, la compilacion la acepta correctamente.gracias por lo que puedas ayudarme.


17-Jun-2011 10:36
Nacho Cabanes (+31)

El problema no tiene que ver con la extensión del archivo, sino con su contenido: puedes poner perfectamente extensión ".txt" a un fichero binario o extensión ".dat" (o cualquier otra) a un fichero de texto.

Tu fallo, como tú mismo dices, está aquí:

read(archClase,clase[i]);

donde ese "clase[i]" procede de:

TNotas = ARRAY[1..NUM_NOTAS] OF Real;

TAlumno = RECORD
nombre:string[10];
notas: TNotas;
END;

TClase = ARRAY [1..LIMITE] OF TAlumno;

Eso no es texto puro, sino datos en formato interno de tu compilador (¿sabes cómo se almacena internamente -en memoria- un número real?  ¿y un array de números reales?)

Por eso, si creas el fichero de texto "a mano" y lo intentas leer mediante esa línea, fallará.

Hay dos posibles soluciones:

1) Crear el fichero desde programa, con una orden "write" similar a ese "read" que no está funcionando. Así será un fichero binario en el formato exacto que tu compilador espera (pero a cambio, si lo creas con FreePascal quizá no se lea bien con Turbo Pascal o con otra versión de Pascal, y viceversa).

2) O bien crear un fichero de texto con el bloc de notas o la herramienta que prefieras, pero para leerlo como texto y luego convertirlo a tu formato interno (te será más fácil si cada dato está en una línea distinta):

readln(fichero, clase[i].nombre);
readln(fichero, clase[i].notas[1]);
readln(fichero, clase[i].notas[2]);


17-Jun-2011 12:44
Nacho Cabanes (+31)

Un fichero que crees con el bloc de notas siempre será un fichero de texto, formado por letras, porque lo has creado con un editor de texto.

Un fichero que crees mediante un programa tuyo puede no ser texto. Por ejemplo, si la variable "edad", de tipo byte, tiene como valor 20 y escribes su valor con "write(fichero, edad);" se escribirá un byte 20, que no corresponde a ningún carácter imprimible, y por tanto no se podrá ver correctamente con el bloc de notas.

Y si el dato no es de tipo "byte" sino de tipo "integer", o "real" o cualquier otro, la situación se va complicando, porque un único número corresponderá a una secuencia de bytes, siguiendo un cierto formato que a veces no es demasiado simple.

En general, los ficheros de ese tipo se tendrán que crear desde tu propio programa, no desde el bloc de notas.


17-Jun-2011 12:46
oscar gomez

Hola Profsor Nacho, gracias por estar siempre aqui con nosotros.

profesor disculpame si no entiendo lo que me comentas respecto a: Eso no es texto puro, sino datos en formato interno de tu compilador ..." me gustaria si pudieras explicarme un poco mejor este apreciacion por que la verdad no entiendo y se que es importantisimo lo que intentas decirme, ojala a traves de una ejemplo quiza entendere mejor a que te refieres exactamente con que lo que tengo no es texto puro, pues yo he creado a traves del block de notas el archivo datos.dat y en el codigo trabajo este archivo como un archivo:text;

he realizado la segunda opcion de solucion que me propones en el procedimiento donde me da el error, pero al hacer el cambio me sale el siguiente error:

PROCEDURE CargarInfo(VAR archClase: TFicheroClase; VAR clase: TClase);
VAR
i: integer;
BEGIN
i:=1;
WHILE NOT eof(archClase) AND (i <= LIMITE) DO {cargamos la info de los 30 primeros alumnos}
BEGIN
 readln(archClase,clase[i].nombre);
         readln(archClase,clase[i].nota[i]);
         readln(archClase,clase[i].nota[i]);
 i:=i+1;
END;
END;


el mensaje de error que me sale ahora es:

" invalid file type "

pòr favor ayudame para que me quede claro, gracias, mil gracias a ti y Antonio por su paciencia y ese Don de enseñar que pocos tienen.


17-Jun-2011 12:48
oscar gomez

Hola Profsor Nacho, gracias por estar siempre aqui con nosotros.

profesor disculpame si no entiendo lo que me comentas respecto a: Eso no es texto puro, sino datos en formato interno de tu compilador ..." me gustaria si pudieras explicarme un poco mejor este apreciacion por que la verdad no entiendo y se que es importantisimo lo que intentas decirme, ojala a traves de una ejemplo quiza entendere mejor a que te refieres exactamente con que lo que tengo no es texto puro, pues yo he creado a traves del block de notas el archivo datos.dat y en el codigo trabajo este archivo como un archivo:text;

he realizado la segunda opcion de solucion que me propones en el procedimiento donde me da el error, pero al hacer el cambio me sale el siguiente error:

PROCEDURE CargarInfo(VAR archClase: TFicheroClase; VAR clase: TClase);
VAR
i: integer;
BEGIN
i:=1;
WHILE NOT eof(archClase) AND (i <= LIMITE) DO {cargamos la info de los 30 primeros alumnos}
BEGIN
 readln(archClase,clase[i].nombre);
         readln(archClase,clase[i].nota[i]);
         readln(archClase,clase[i].nota[i]);
 i:=i+1;
END;
END;


el mensaje de error que me sale ahora es:

" invalid file type "

pòr favor ayudame para que me quede claro, gracias, mil gracias a ti y Antonio por su paciencia y ese Don de enseñar que pocos tienen.


17-Jun-2011 13:24
Nacho Cabanes (+31)

Por cierto, tu programa, aun usando ficheros de texto, necesita algunas mejoras.

- No compruebas errores de lectura.

- Debes intentar que sea lo más modular posible: ya que hay una función que se encarga de manejar el fichero, que sólo ella conozca el fichero, en vez de ser un dato del programa principal que se le pasa como parámetro.

-La media que calculas es incorrecta: has previsto un límite de 30 alumnos, pero quizá haya menos en el fichero (5 en el caso que pones de ejemplo) así que no deberías dividir entre 30 sino entre la cantidad real de alumnos.

Una versión un poco más afinada, usando ficheros de texto (y sin comprobar todavía errores de lectura) podría ser (ya sabes que al copiar y pegar desaparecerán las tabulaciones, pero aun así lo prefiero a adjuntar el archivo, para que le puedas echar un vistazo sin necesidad de descargarlo):

(Edito: he cambiado tus tabulaciones por espacios, para que se lea correctamente incluso en pantalla)

PROGRAM DatosDeAlumnos;

CONST
   LIMITE = 30;
   NUM_NOTAS = 2;

TYPE
   TNotas = ARRAY[1..NUM_NOTAS] OF Real;

   TAlumno = RECORD
       nombre:string[10];
       notas: TNotas;
   END;

   TClase = ARRAY [1..LIMITE] OF TAlumno;


PROCEDURE CargarInfo(nombre: string; VAR clase: TClase;
   VAR cantidadLeida: integer);
VAR
   archClase: text;
   i, j: integer;
BEGIN
   assign(archClase, nombre);
   reset(archClase);
   i:=1;
   {cargamos la info de los 30 primeros alumnos... o menos}
   WHILE NOT eof(archClase) AND (i <= LIMITE) DO
   BEGIN
       readLn(archClase,clase[i].nombre);
       {y cada alumno tiene varias notas}
       FOR j := 1 TO NUM_NOTAS DO
           readLn(archClase,clase[i].notas[j]);
       i:=i+1;
   END;
   close(archClase);
   {Si el contador indica 6, es que no he podido leer el 6º dato }
   cantidadLeida := i-1;
END;

PROCEDURE Estadisticas(clase: TClase; cantidad: integer);
VAR
   i, j:integer;
   suma: real;
BEGIN
   suma:=0;
   FOR i:=1 TO cantidad DO {para el alumno i-esimo}
       FOR j:=1 TO NUM_NOTAS DO {cada asignatura del alumno i}
           suma:= suma + clase[i].notas[j]; {se acumulan todas}
   writeln('Total de alumnos analizados: ', cantidad );
   writeln('La nota media de la clase para todas las asignaturas es: ',
       suma/(NUM_NOTAS*cantidad):5:2 );
END;

VAR
   clase: TClase;
   cantidad: integer;

BEGIN
   CargarInfo('datos.txt', clase, cantidad);
   Estadisticas(clase, cantidad);  
END.



Para este programa, el fichero de datos (de texto) debería ser así:

mario
3.5
3.9
jose
4.2
3.7
pedro
2.9
3.3
alicia
4.9
2.8
marta
4.3
4.1


17-Jun-2011 15:28
oscar gomez

Gracias profesor Nacho, que alegria me da que gracias a tu excelente e impecable explicacion haya podido realizarlo al fin con exito y lo mas importante haber entendido claramente las diferencias entre archivos de texto y los archivos con tipo , gracias por que me has aclarado muchas dudas y cada vez me ayudas a mejorar y a ir por el buen camino de realizar programas modulares y entendibles, gracias de verdad, por que con esto ya puedo pasar a otro tema (la parte de listas porejemplo y la de programacion  de juegos en pascal a traves de unidades...) para seguir mi aprendizaje, que suerte tienen tus alumnos donde dictas clases y tambien nosotros que nos das la oportunidad de recibir tu luz y enseñanza mil gracias y por supuesto lo hago tambien extensible a Antonio.


17-Jun-2011 17:13
oscar gomez

Hola profesor Nacho, mira te habia escrito antes indicandote que me funciona ya el programa, sin embargo al revizar manualmente, los resultados, segun el archivo de texto:datos.txt:

mario
3.5
3.9
jose
4.2
3.7
pedro
2.9
3.3
alicia
4.9
2.8
marta
4.3
4.1

en pantalla se me muestra como resultado:
la nota media de la clase para todas las asignaturas es: 3.13

la respuesta correcta no seria:
(3.5+3.9+4.2+3.7+2.9+3.3+4.9+2.8+4.3+4.1)/10 = 3.76

por que en la instruccion del programa:

writeln('la nota media de la clase para todas las asignaturas es:',suma/(NUM_NOTAS * cantidad):5:2);

por que multiplicas por cantidad? pues segun esto tendriamos que
37.6 ( que es la suma de todas las notas) / 10 (notas)*cantidad(numero de alumnos del fichero) =37.6/(10*5)= 0.76

me podrias explicar esta parte que te comento en este mensaje...mil gracias y disculpa por que no habia probado manualmente los resultados,tan solo lo corregi y compilo y ejecuto con respuesta la cual es la que no entiendo. mil gracias


18-Jun-2011 11:58
Nacho Cabanes (+31)

Decías

> por que en la instruccion del programa:

> writeln('la nota media de la clase para todas las asignaturas es:',suma/(NUM_NOTAS * cantidad):5:2);

> por que multiplicas por cantidad? pues segun esto tendriamos que
37.6 ( que es la suma de todas las notas) / 10 (notas)*cantidad(numero de alumnos del fichero) =37.6/(10*5)= 0.76

Si miras con detalle la función que carga desde el fichero, verás que "cantidad" no es lo mismo que la variable "LIMITE" que tú usabas antes: no vale 10, sino la cantidad de datos que realmente había en el fichero (i-1, para más detalles).

Por tanto, sería = 37.6 / (2*5) = 3.76


Por cierto, una pregunta anterior que no había contestado:

> el mensaje de error que me sale ahora es:
> " invalid file type "

Era por que intentabas abrir un fichero de texto, leer usando ReadLn... pero lo habías declarado como "file of XXX", en vez de como "text".


18-Jun-2011 22:03
oscar gomez

Hola Profesor Nacho, como siempre no dejare de dartelas por que tener tu ayuda es como una bendicion para nosotros.

profesor, es super entendible lo que me explicas, pero el resultado en ejecucion del programa que te adjunte en el mensaje anterior muestra como resultado de la media: 3.14 y no 3.76
hice dentro del procedimiento, Estadisticas, dos writeln, para verificar que estaba almacenando la variable suma y la variable cantidad y resulta que la variable suma esta ok, es decir muestra suma = 37.60, pero la variable cantidad esta almacenando 6 en vez de 5, y no comprendo el porque, puesto que en el procedimiento CargarInfo, se devuelve como parametro por referencia la variable cantidadleida que se supone se hace: cantidadleida:=i-1, lo cual deberia darnos darnos 5, que seria el regreso para esa variable por referencia, pues cuando i valga 6, tendremos en el while que 6<=5 lo cual nos hece salir de dicho bucle. la verdad no se que este mal entonces profesor, podrias ayudarme en que esta fallando el programa??? mil gracias por tu ayuda.


21-Jun-2011 22:18
Nacho Cabanes (+31)

No hace falta que repitas la pregunta. Miro el foro cuando puedo, y mi tiempo no se puede estirar más... por mucho insistas.

Sin ver cómo ha quedado tu fuente completo, no te puedo señalar el fallo... pero es que no debería ser necesario, porque basta que pongas algún "WriteLn" es las partes del programa en las que tengas dudas, para comprobar si los valores de las variables son los que esperabas.

El problema puede ser algo tan sencillo como varias líneas en blanco al final del fichero de datos, que hagan que el contador de líneas leídas sea mayor de lo que esperas.

Pero insisto, la mejor forma es que te asegures de que las variables tienen el valor que deben, ya sea con la ayuda de un depurador o simplemente con unas pocas órdenes "WriteLn" repartidas por varios puntos clave del programa.


22-Jun-2011 12:40
oscar gomez

Gracias profesor Nacho, ante todo pedirle disculpas por haberle reenviado el mensaje, pero creame que no fue mi intencion hacerlo con el fin de agilizar quiza tu orientacion por que desde que entre ha este foro se de tu poco tiempo y me consta, y mal haria o seria absurdo de mi parte querer intentar que estes cada vez que te necesitemos, por favor disculpeme te loo reenvie por que quiza sin darme cuenta estaba algo desesperado por que no me salia pero tambien en ello nos enseñas a tener paciencia y te lo agradecemos inmensamente.gracias por ser profesor y ademas inmensa persona por que quien ayuda a quienes como nosotros lo necesitamos te engrandece cada dia mas, mil gracias.

PROFESOR YA HE SOLUCIONADO EL ERROR Y ME FUNCIONA CORRECTAMENTE, SIN EMBARGO HACIENDO PRUEBAS CON VARIOS WRITELN COMO ME LO SUGERISTE Y QUE GRACIAS A ELLO ENCONTRE EL ERROR, SI QUE ME SURGIO UNA DUDA QUE QUIERO PLANTEARTE PUES NO ENTIENDO POR QUE ALGUNOS WRITELN EN EL PROCEDIMIENTO QUE TE ADJUNTO NO ME DABAN SU VISUALIZACION EN PANTALLA,PODRIAS AYUDARME A DECIRME EL PORQUE NO SE MUESTRAN SUS VALORES EN PANTALLA DENTRO DEL PROCEDIMIENTO :

PROCEDURE CargarInfo( nombre:string;var clase: TClase;var cantidadleida:integer);
VAR
i,j: integer;
       archclase:text;
BEGIN
i:=1;
       assign(archclase,nombre);
       reset(archclase);
       {cargamos la informacion de los 30 alumnos ...o menos}
WHILE NOT eof(archclase) AND (i <=LIMITE) DO
BEGIN
          read(archClase,clase[i].nombre);
            {y cada alumno tiene varias notas}
          for j:=1 to NUM_NOTAS do
             readln(archClase,clase[i].notas[j]);
         i:=i+1;
   { writeln(i);}
END;
      { writeln(i);}
         close(archclase);
      {writeln(i); }
  {si el contador indica 6, es que no he podido leer el 6 dato}
    cantidadleida:=i-1;
  { writeln(cantidadleida); }

END;

MIL GRACIAS NACHO.



24-Jun-2011 16:59
Nacho Cabanes (+31)

Decias...

>  NO ENTIENDO POR QUE ALGUNOS WRITELN EN EL PROCEDIMIENTO QUE TE ADJUNTO NO ME DABAN SU VISUALIZACION EN PANTALLA

La forma de saberlo es no usar simplemente

writeln(i);

sino algo más detallado, como

writeln('Al salir de FOR vale ', i);

o al menos numerar las órdenes para saber exactamente por dónde pasas:

writeln('2', i);


24-Jun-2011 17:48
oscar gomez

cordial saludo profesor Nacho.

profesor he tenido en cuenta lo que me dices en tu respuesta pero aun asi no se me ve ninguno de los writeln que te coloco encerrados como {  }********
obviamente te los pongo asi para que sepas de cuales writeln te hablo en el procedimeinto que te comentaba en mensaje pasado:

PROCEDURE CargarInfo( nombre:string;var clase: TClase;var cantidadleida:integer);
VAR
i,j: integer;
       archclase:text;
BEGIN
i:=1;
       assign(archclase,nombre);
       reset(archclase);
       {cargamos la informacion de los 30 alumnos ...o menos}
WHILE NOT eof(archclase) AND (i <=LIMITE) DO
BEGIN
         read(archClase,clase[i].nombre);
           {y cada alumno tiene varias notas}
         for j:=1 to NUM_NOTAS do
             readln(archClase,clase[i].notas[j]);
         i:=i+1;
   { writeln('el valor aqui es:', i);}***************
END;
     { writeln('el valor aqui es:',i);}
         close(archclase);
     {writeln(i); }*****************
 {si el contador indica 6, es que no he podido leer el 6 dato}
   cantidadleida:=i-1;
 { writeln('el valor es: ',cantidadleida); }***************

ADEMAS QUERIA PREGUNTARTE CUAL PODRIA SER EL ENUNCIADO DEL EJERCICIO PARA TENER ENCUENTA USAR …        
writeln('La nota media de la clase para todas las asignaturas es: ',
       suma/(NUM_NOTAS*cantidad):5:2 );

PUES  IGUAL MIRANDO EL ARCHIVO DEL EJEMPLO SE QUE EN TOTAL HAY  UNA CANTIDAD DE 10 NOTAS, Y HUBIESE HECHO ENTONCES
writeln('La nota media de la clase para todas las asignaturas es: ',suma/10 );

mil gracias por tu tiempo y tues excelentes enseñanzas.


25-Jun-2011 01:27
Nacho Cabanes (+31)

No entiendo bien qué problema tienes.

Primero, si repites varias líneas como

{ writeln('el valor aqui es:', i);}***************

no sabrás por cual pasas. Numéralas.

En segundo lugar, ¿por qué las llaves? ¿Las pones cuando lo copias en el foro o son parte del fuente? Obviamente, si son parte del fuente, esos "writeln" no funcionarán, porque son parte de un comentario.

Un posible tercer motivo para que "no funcione" sería si no lo ves en pantalla porque haya algún "clrscr" poco después. Mientras haces pruebas, puedes provocar una pausa añadiendo un "ReadLn" tras cada "WriteLn" (sin llaves, claro).


25-Jun-2011 12:16
oscar gomez

Gracias profesor Nacho efectivamente era un clrscr el que me impedia ver los writeln que te mencionaba, y que te mostre entre {} por que eran solo pruebas que estaba realizando y que por lo tanto no son parte del programa como tal.

profesor me gustaria me indicaras cual podria ser el enunciado correcto para este programa, respecto a lo que te mencione en el mensaje anterior:

PARA TENER ENCUENTA USAR EN LA SOLUCION DEL MISMO: …        
writeln('La nota media de la clase para todas las asignaturas es: ',suma/(NUM_NOTAS*cantidad):5:2 );

PUES  IGUAL MIRANDO EL ARCHIVO DEL EJEMPLO SE QUE EN TOTAL HAY  UNA CANTIDAD DE 10 NOTAS, Y HUBIESE HECHO ENTONCES
writeln('La nota media de la clase para todas las asignaturas es: ',suma/10 );

MIL GRACIAS


26-Jun-2011 19:41
Nacho Cabanes (+31)

Decías

> cual podria ser el enunciado correcto para este programa

Tú sabrás que es lo que tiene que hacer tu programa... porque si no lo sabes ni tú... mal vamos... ;-)

> PUES  IGUAL MIRANDO EL ARCHIVO DEL EJEMPLO SE QUE EN TOTAL HAY  UNA CANTIDAD DE 10 NOTAS, Y HUBIESE HECHO ENTONCES
> writeln('La nota media de la clase para todas las asignaturas es: ',suma/10 );

Sí, podrías. Pero es que lo ideal es que un programa se comporte correctamente aunque cambien los datos de entrada. Por eso, no se trata de que tu programa sólo trabaje bien cuando haya 10 datos, sino de que analice el fichero de la forma más fiable que se te ocurra, para que no falle cuando el número de datos sea distinto.


27-Jun-2011 10:05
oscar gomez

ok gracias profesor Nacho, sin embargo por supuesto que se lo que hace el programa, de lo contrario no hubiese podido hacerlo, lo que quiza queria era un mejor enunciado dada tu experiencia como profesor y dado que el hablaba de 30 alumnos en la clase de los cuales se toma 5 alumnos. lo que me dices es totalmente cierto respecto a si se modifica la cantidad de datos porejemplo. mil gracias.






(No se puede continuar esta discusión porque tiene más de dos meses de antigüedad. Si tienes dudas parecidas, abre un nuevo hilo.)