Función fread y saltos de línea

Iniciado por NathanD, 19 Marzo 2013, 00:25 AM

0 Miembros y 1 Visitante están viendo este tema.

NathanD

Buenas a todos, mi problema es que no entiendo ciertas cosas sobre los ficheros, más concretamente la diferencia entre ficheros binarios y de texto, las funciones para cada tipo...

Por ejemplo, en un examen de otro día, teníamos en un archivo de extensión .dat (entiendo que es binario, así que lo abrí como tal). Se trataba de un censo con la información de los habitantes, y si cumplían ciertos requisitos, había que copiarlos a un fichero .txt. No se me ocurrió otra forma que hacerlo con fgets, para tener en cuenta los saltos de línea, asumiendo que cada habitante está en una línea (¿cómo puedo hacerlo con fread?). Y claro, lo hice mal (y éso que con fgets funciona sin problema). Por éso, no tengo nada claro por qué con una función sí y con otra no, y cómo usarla...

Gracias de antemano y saludos.

rir3760

Cita de: NathanD en 19 Marzo 2013, 00:25 AMmi problema es que no entiendo ciertas cosas sobre los ficheros, más concretamente la diferencia entre ficheros binarios y de texto
La diferencia principal entre un stream binario y uno en modo texto es: en este ultimo el carácter o caracteres utilizados para indicar el avance de linea (por ejemplo '\r' + '\n' en MS Windows) se convierten de forma transparente a '\n' en las operaciones de lectura. Y cuando escribes en el archivo todo '\n' se convierte apropiadamente (siguiendo el ejemplo cada '\n' se sustituye por el par '\r' + '\n').

Eso no sucede con un stream en modo binario.

Cita de: NathanD en 19 Marzo 2013, 00:25 AMNo se me ocurrió otra forma que hacerlo con fgets, para tener en cuenta los saltos de línea, asumiendo que cada habitante está en una línea (¿cómo puedo hacerlo con fread?).
No es posible ya que fgets lee por linea (si no sobrepasa el máximo indicado) mientras que fread lee por bloque, puedes utilizar esta ultima para leer N caracteres pero no sabrás cuantas lineas se leyeron (debes escanear el bloque para contar manualmente los '\n').

Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language

NathanD

Muchas gracias por responder. Entonces, si lo hago con fread, tendría que mirar yo mismo manualmente los '\n' (si es que se supone que para habitante del censo del fichero .dat hay una línea).

Gracias y saludos

rir3760

Cita de: NathanD en 19 Marzo 2013, 10:52 AMEntonces, si lo hago con fread, tendría que mirar yo mismo manualmente los '\n'
Correcto

Cita de: NathanD en 19 Marzo 2013, 10:52 AMes que se supone que para habitante del censo del fichero .dat hay una línea
Entonces lo mejor es utilizar fgets para leer por linea (y por ende por registro). Si necesitas separar la linea en componentes (nombre, dirección, etc.) puedes utilizar funciones como strtok.

Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language

NathanD

Cita de: rir3760 en 19 Marzo 2013, 16:14 PM
Correcto
Entonces lo mejor es utilizar fgets para leer por linea (y por ende por registro). Si necesitas separar la linea en componentes (nombre, dirección, etc.) puedes utilizar funciones como strtok.

Un saludo
Éso es lo que pienso yo, pero nos dijeron que con ficheros binarios había que utilizar fread, no fgets...

rir3760

Supongo se refiere (¿Tu profesor?) a que si almacenas en un archivo un bloque de memoria con fwrite debes leerlo con fread. El caso usual es cuando se almacena en el archivo un array de estructuras con campos de tipo int, double, etc.

Pero si ese es el caso ya no estamos tratando con un archivo cuyo contenido son lineas de texto.

Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language

NathanD

#6
Una última cuestión. Suponiendo que el censo contiene datos de miles de personas, ¿cuál sería la estrategia para ver cada una de ellas, usando fread? Porque con fgets es sencillo, pero no tengo claro cómo sería con fread, con tantos datos. Porque la cuestión es que cada persona tendrá varios datos, y necesito tener en cuenta uno en concreto (la fecha de nacimiento) para escoger a quién copiar en un segundo fichero .txt que crearé.

rir3760

Si un array de estructuras se almaceno en un archivo mediante fwrite debes leerlo con fread. Lo usual es leer un bloque de estructuras y almacenarlo en un array, después de procesarlo lees otro bloque, eso lo implementas mediante un bucle.

Mas o menos así:
#include <stdio.h>
#include <stdlib.h>

#define NOM_ENTRADA  "Entrada.dat"
#define LONG_MAX_CADENA  128
#define MAX_REGS  64

struct reg {
   char nombre[LONG_MAX_CADENA];
   char direccion[LONG_MAX_CADENA];
   struct {
      int dia;
      int mes;
      int año; /* Es a n i o pero el foro lo cambia ... */
   }fnac;
};

int main(void)
{
   FILE *entrada;
   struct reg reg[MAX_REGS];
   size_t num_regs;
   
   if ((entrada = fopen(NOM_ENTRADA, "rb")) == NULL){
      perror(NOM_ENTRADA);
      return EXIT_FAILURE;
   }
   
   while ((num_regs = fread(reg, sizeof(struct reg), MAX_REGS, entrada)) > 0){
   
      /* Procesamos "num_regs" registros */
     
   }
   fclose(entrada);
   
   return EXIT_SUCCESS;
}


Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language

NathanD

#8
Hay una cosa en el código que no entiendo (siento ser tan pesado). Cuando hago lo siguiente:


while( ! feof(fichero) )
   {
          num_regs = fread(reg, sizeof(struct reg), MAX_REGS, entrada);
          /*********************/


Ahí se copia todo el contenido del fichero en reg[0].nombre, lo cual no entiendo muy bien.

Gracias de antemano y perdón por las molestias

Edito:

Vale, era porque en el fichero no había escrito con fwrite. Ahora creo que lo entiendo todo. Muchas gracias por tu ayuda y paciencia.