|
Al obtener datos desde un dispositivo de entrada, como por ejemplo, leyendo un fichero o similar, a menudo los leguajes de programación cuentran con alguna función o método relacionado con la entrada/salida que nos indica si hemos alcanzado el fin de los datos. Esa función o método devuelve algún tipo de indicación acerca de si hemos alcanzado el fin de fichero.
Típicamente, esa indicación es un simple booleano, que suele ser true cuando hemos alcanzado el fin del fichero y false si todavía no lo hemos hecho. Al fin de fichero se le llama en inglés End Of File, abreviado EOF, por eso las funciones que comprueban si se ha alcanzado el fin del fichero suelen contener "EOF" en su nombre. La estructura típica para leer un fichero hasta alcanzar su fin es siempre la misma... utiliza un bucle while en cuya condición se comprueba si se ha alcanzado el fin del fichero. En pseudocódigo, podría ser algo así: abrir fichero
mientras no fin de fichero
leer dato
procesar dato
fin mientras
cerrar fichero
Si fuera necesario salir del bucle por cualquier otro motivo, incuiremos una condición de finalización en la codición del while booleano salir=false
abrir fichero
mientras no fin de fichero y no salir
leer dato
si se produce condición de salida
salir=true
si no
procesar dato
fin si
fin mientras
cerrar fichero
por ejemplo, observa este código en PHP $fichero=@fopen("ejemplo.txt","r");
while (!feof($fichero)) {
//leer del fichero
//y procesar
}
fclose($fichero);
En algunos lenguajes, esta forma de leer ficheros va cayendo en desuso (por ejemplo, la plataforma .NET), debido en parte a que la detección del fin de fichero suele ser muy dependiente del sistema operativo subyacente por una parte, y por la otra a que cada vez es más innecesario leer ficheros hasta el final, salvo en unas pocas operaciones. La plataforma .net, por ejemplo, dispone de otros mecanismos para conocer si se ha alcanzado el fin del fichero, pero claramente no son prioritarios en la E/S. En esta plataforma, sólo existen métodos para conocer si hemos llegado al fin del fichero cuando hacemos lecturas binarias. Es decir, byte a byte o en bloques de bytes. La clase BinaryReader, por ejemplo, dispone de un método llamado PeekChar(), que nos informa del próximo byte de un fichero, pero sin retirarlo del fichero. Si devuelve un valor positivo, es que todavía se puede leer un byte. Si devuelve -1, es que no hay más bytes disponibles. //este método lee de un fichero hasta su fin
//e imprime el valor decimal de cada byte
FileStream f=new FileStream("c:\\ejemplo.txt", FileMode.Open);
BinaryReader br = new BinaryReader(f);
int b=0;
while (br.PeekChar()!=-1)
{
b = br.ReadByte();
Console.Write("{0} ",b);
}
Análogamente, esta misma clase dispone de un método ReadByte(), similar a Peek(), pero que sí retira el byte del fichero, y también devuelve -1 si el byte no se pudo leer. Podemos utilizar (Peek()!=-1) como señal de fin de fichero, o bien no utilizarlo, y utilizar solo ReadByte(), tomando el valor -1 como un centinela. en cuyo caso podríamos utilizar la estructura de una Entrada de datos con centinela. //este método lee de un fichero hasta su fin
//e imprime el valor decimal de cada byte
FileStream f=new FileStream("c:\\ejemplo.txt", FileMode.Open);
BinaryReader br = new BinaryReader(f);
int b=0;
do
{
b = br.ReadByte();
if (b != -1) //centinela
Console.Write("{0} ", b);
} while (b != -1);
Existen otros sistemas para leer bloques de bytes. Por ejemplo, el método byte[] ReadBytes (int count) intenta leer el número de bytes que se le pide como parámetro, y devuelve un array con los bytes leidos. Si devuelve un array de 0 bytes, es que no ha podido leer más. FileStream f=new FileStream("c:\\ejemplo.txt", FileMode.Open);
BinaryReader br = new BinaryReader(f);
byte[] ba;
int leidos = 0;
//usamos do-while porque siempre intentamos
//leer algo del fichero
do
{
//intentaremos leer 5 bytes
ba = br.ReadBytes(5);
//la longitud de ba es el número de bytes
//que se han podido leer
leidos = ba.Length;
//si hemos podido leer algo, es que no
//estamos en el fin de fichero
if (leidos > 0)
{
//imprimir contenido de ba
foreach (byte b in ba) {
Console.WriteLine("{0} ", b);
}
}
} while (leidos > 0);
Por último, solo recalcar que cada vez menos se hace uso de esta forma de leer ficheros, excepto para la manipulación a nivel de bytes. En otros casos no suele resultar práctico. Para la manipulación de ficheros de texto, suelen existir clases y métodos que la realizan con gran eficacia, incluso con opciones avanzadas como manipulación de las distintas tablas de carácteres (aunque ASCII sigue siendo ampliamente utilizado, es muy pobre... y existen otras alternativas, como UTF-8, UTF-16, y la conocida iso-8859-1, que utilizamos en Europa occidental y América). También es más común cada vez el intercambio de datos a través de algún estándar que asegure una estructura común, como XML. Los lenguajes de programación cada vez más poseen librerías para tratar con ficheros XML. En cuanto a los datos binarios, si estamos tratando con objetos complejos u otras estructuras compuestas, los lenguajes tienen clases encargadas de grabar y recuperar objetos, y si no, recurrimos a sistemas gestores de bases de datos orientados a objetos o relacionales. |