Duda al escribir ficheros

Iniciado por Feynmann, 23 Marzo 2014, 16:03 PM

0 Miembros y 3 Visitantes están viendo este tema.

amchacon

#10
Te has pasado a C++ a C... Haz lo todo en C entonces, no mezcles lenguajes.

Porque usas cin.getline con un fichero?? Su primer argumento debe ser un array char.

Entiendo que querías leer una linea del fichero, la función que buscas es fgets.

Cuando eres novato, mejor no mezclar lenguajes. Te evitar as errores extraños
Por favor, no me manden MP con dudas. Usen el foro, gracias.

¡Visita mi programa estrella!

Rar File Missing: Esteganografía en un Rar

Feynmann

uff fgets? vale voy a ello!
lo mezclo por que no me empano mucho..

Entonces que me aclare.. para leer una linea del datos.txt uso el fgets la inserto en salida.txt y luego como me voy a la segunda linea del datos.txt?
Novato curioso, me gustaria aprender a programar bien en C/C++ por eso estoy aqui. Pero puedo echar una mano a cualquiera que me lo pida en temas de electronica!

eferion

fopen, fwrite, fread son funciones de C.

Puedes identificar de forma más o menos sencilla C de C++ por la sintaxis.

Los objetos de C++ tienen una forma tal que:

Código (cpp) [Seleccionar]

ofstream stream( "ruta", ios_base::out );
stream << buffer;
stream.close( );


Mientras que el código C se parece más a


FILE *fichero = fopen( "ruta", "w+" );
fwrite( fichero, sizeof( algo ), 20, buffer );
fclose( fichero );


En C++ se llaman a miembros de las clases mientras que en C se llama a funciones.

amchacon

Por cierto no te lo he dicho, cuando quieras saber como es tal función busca en google "fgets c++". El primer resultado que te marca es de una pagina muy buena.

Ya sé que fgets es de C, pero como la página se llama "C++ reference" lo tienes que poner así xD:
http://www.cplusplus.com/reference/cstdio/fgets/

Para no mezclar lenguajes, lo mejor esque uses un compilador de C y no de C++ (no sé como compilas, pero muchos programas de desarrollo usan el compilador de C cuando la extensión del archivo es .c). De esa forma el compilador te recordará mis palabras con sus amorosos mensajes de error ;D

Cita de: Feynmann en 24 Marzo 2014, 11:59 AMEntonces que me aclare.. para leer una linea del datos.txt uso el fgets la inserto en salida.txt y luego como me voy a la segunda linea del datos.txt?
Más fácil todavía, cuando lees de un archivo automáticamente avanzas de posición.

De modo que esto:

Código (cpp) [Seleccionar]
fgets(cadena,256,archivo);

while (!feof(archivo)) // mientras no se llegue al final del archivo...
{
   printf(cadena);
   fgets(cadena,256,archivo);
}


Te imprimiría el archivo completo por pantalla línea a línea.
Por favor, no me manden MP con dudas. Usen el foro, gracias.

¡Visita mi programa estrella!

Rar File Missing: Esteganografía en un Rar

Feynmann

Compilo con visual studio 2010!
Me dará muchos problemas?

Voy a seguir intentandolo... a ver si me aclaro! muchas gracias chicos!
Que dificil y arduo es esto de C++, madre mia! Me cuesta mucho comprender la programación.. yo y mis limitaciones :( jeje


Voy a pelearme con ello y os comento, saludos!
Novato curioso, me gustaria aprender a programar bien en C/C++ por eso estoy aqui. Pero puedo echar una mano a cualquiera que me lo pida en temas de electronica!

amchacon

Visual studio? Joder que valiente xD

No digo que sea malo pero es bastante complejo, yo tiraría más por Codeblocks pero bueno.

Lo que te falla es la teoría más que nada, yo me centraría en un solo lenguaje y cuando ya lo dominara miraría el otro (aunque son bastante parecidos).

Y por supuesto algún libro que te lo explique todo desde cero no iría mal... También tienes esta pagina:
http://www.minidosis.org/#/

Todo lo que necesitas aprender sobre C++. Con ejercicios y todas las lecciones paso a paso.
Por favor, no me manden MP con dudas. Usen el foro, gracias.

¡Visita mi programa estrella!

Rar File Missing: Esteganografía en un Rar

Yoel Alejandro

Mi opinión personal: Un programa como éste yo lo haría siempre en C. Si quiero compilar con un compilador de C++ cambiaría las cabeceras a <cstdio>, <cstdlib>, etc., y listo.

¿La razón? Como bien dijo un autor que respeto, C es un lenguaje intencionalmente escueto. Se maneja con un conjunto mínimo de funciones de la biblioteca estándar. Ese conjunto está reducido a ta punto que es difícil lograr que la tarea de una función la realice otra (salvo algunas excepciones de <stdio.h> como usar fgetc(stdin) en lugar de getchar()), es decir, prácticamente las funciones de su biblioteca estándar no se duplican. De hecho, no hay duplicidad en el ejemplo que cité, porque sólo existe fgetc como función de biblioteca mientras getchar() está implementado como una macro a partir de aquélla.

Yo creo que no se puede decir lo mismo de C++. El mundo en este lenguaje es inmenso. Hay clases y métodos para todos gustos, tamaños y colores. Lo cual puede ser abrumante.

Me explico mejor, supóngase que un programador principiante busca ayuda en internet sobre un código que realice determinada tarea en C. Por ejemplo: "leer un fichero de texto y escribir su contenido en otro fichero, convertiendo las palabras a mayúsculas". Si el código es "óptimo" o "correcto", y se limita a la biblioteca estándar, lo más probable es que al menos el 50% de los resultados de su búsqueda sean similares o muy similares entre sí. Es que C es tan mínimo que casi hay una sola manera "perfecta" de hacer las cosas. Cuando mucho dos.

Si buscas lo mismo en C++, creo que habrá mucha más variedad y diversidad de maneras de resolver el problema (con o sin flujos, usando o no la clase string, etc.). Entonces, el principiante de 10 resultados que busca en internet para este problema, ¡ encuentra 10 soluciones diferentes ! Y Aquí empieza a embromarse. ¿cuál es mejor, cuál es peor, por qué una y no la otra?

Simplemente uso C++ cuando se requieren clases, de otro modo para operaciones básicas de procesar cadenas, números, ficheros, E/S por consola, etc., me remito a C. No se si estas opiniones son porque me gusta llegar a la forma más simple y breve de resolver las cosas, o porque soy un romántico que decidió apegarse al pasado de C, jejeje.

En cuanto a tu programa, me permito algunas recomendaciones para perfeccionarlo:

(1) Abre el fichero que entrada en modo de solo lectura:

fichero = fopen( nombre, "r" )

con "r" en lugar de "r+".

(2) Abre el fichero de salida en modo de escritura:

fichero2 = fopen( nombre2, "w")

(3) Para leer una línea del flujo, puedes usar la función fgets(char *buffer, int n, FILE *stream). El primer argumento buffer debe ser un arreglo de char, de al menos n caracteres de capacidad. El segundo argumento es uno más que los caracteres a leer (se deja uno más, para que fgets() coloque automáticamente el nulo de terminación). El tercer argumento es el apuntador a archivo abierto. Ten en cuenta que el salto de línea '\'n se copia al arreglo sólo si tiene espacio "para caber", o sea, si la cantidad de caracteres leídos antes de él es menor a (n-1). Además, si fgets() no pudo leer (si encuentra el fin de archivo), devuelve NULL.

Te preparé un sencillo código que abre el fichero como lectura, toma sus líneas y las escribe al fichero2, además imprime por pantalla lo que va leyendo para verificar como marcha del programa.
Código (cpp) [Seleccionar]

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main( ) {

   FILE *fichero;
   FILE *fichero2;
   char buffer[1001]; /* bufer de linea, 1000 caracteres */

   char nombre[11] = "datos.txt";
   char nombre2[11]= "salida.txt";

   fichero = fopen( nombre, "r" );  // Fichero datos.txt desde el que leo los datos.
   fichero2= fopen( nombre2, "w");  // Fichero salida.txt donde escribire los datos.
   if ( fichero == NULL ) {
      printf( "Fichero '%s' no se pudo abrir.\n", nombre ); /* error */
      return -1;
   }
   if ( fichero2 == NULL ) {
      printf( "Fichero '%s' no se pudo abrir.\n", nombre2 ); /* error */
      return -1;
   }

   /* Mensaje al usuario */
   printf( "\nLeyendo los datos del fichero \"%s\":\n", nombre );

   /* Leer linea a linea, ponerlo en buffer y pasarlo al fichero2 convertido
    * a mayusculas */
  linea = 1;
   while ( !feof(fichero) ) {
      if ( fgets( buffer, 1001, fichero ) != NULL )
         printf("Linea %d: \n\t%s", linea++, buffer );
   }

   /* cerramos los ficheros abiertos */
   if( !fclose(fichero) )
      printf( "Fichero '%s' cerrado con exito\n", nombre );
   else
   {
      printf( "Error: fichero '%s' NO CERRADO\n", nombre );
      return -1;
   }

   if( !fclose(fichero2) )
      printf( "Fichero '%s' cerrado con exito\n", nombre2 );
   else
   {
      printf( "Error: fichero '%s' NO CERRADO\n", nombre2 );
      return -1;
   }

   getchar();
   return 0;
}


Para el fichero de entrada:

Hola
Mundo
Hugo Paco Luis

el programa produce la salida:

Leyendo los datos del fichero "datos.txt":
Linea 1:
Hola
Linea 2:
Mundo
Linea 3:
Hugo Paco Luis
Linea 4:

Fichero 'datos.txt' cerrado con exito
Fichero 'salida.txt' cerrado con exito

Nota que al final imprime una línea vacía, ésto es porque el fichero está terminado en un return (un '\n'). Se podría eliminar ese defecto inspeccionando el contenido copiado al buffer. El valor de retorno de main() en caso de error es -1, que es más usual en lugar de 1.

==================
NOTAS. Una alternativa más breve a:

   fichero = fopen( nombre, "r" );
   if ( fichero == NULL ) {
   printf( "Fichero '%s' no se pudo abrir.\n", nombre );      /* error */
   return -1;
   }

es:

   if ( ( fichero = fopen( nombre, "r" ) ) == NULL ) {
   printf( "Fichero '%s' no se pudo abrir.\n", nombre );      /* error */
   return -1;
   }

Saludos, Yoel.
P.D..-   Para mayores dudas, puedes enviarme un mensaje personal (M.P.)

rir3760

Cita de: yoel_alejandro en 24 Marzo 2014, 17:21 PMpreparé un sencillo código que abre el fichero como lectura, toma sus líneas y las escribe al fichero2, además imprime por pantalla lo que va leyendo para verificar como marcha del programa.
Dos recomendaciones:

* No hay necesidad de generar manualmente el mensaje de error, en su lugar se puede utilizar la función perror (prototipo en <stdio.h>).
* Ya que el valor de retorno de un programa en salida anormal es implementation defined es mejor utilizar la macro EXIT_FAILURE (definida en <stdlib.h>).

Cita de: yoel_alejandro en 24 Marzo 2014, 17:21 PMNota que al final imprime una línea vacía, ésto es porque el fichero está terminado en un return (un '\n'). Se podría eliminar ese defecto inspeccionando el contenido copiado al buffer.
Tal como esta el programa este no puede imprimir una linea en blanco salvo la obviedad de que el archivo de entrada ... tenga una linea en blanco al final de este.

Pero si la entrada es:
Hola
Mundo
Hugo Paco Luis

Entonces no hay forma de que el programa reporte cuatro lineas.

Otras dos observaciones:

* El uso de feof en el bucle es innecesario:
linea = 1;
while ( !feof (fichero) ) {
   if ( fgets ( buffer, 1001, fichero ) != NULL )
      printf ("Linea %d: \n\t%s", linea++, buffer );
}

Ya que no se recomienda el uso de feof (salvo contados escenarios) se puede eliminar esta reduciendo el bucle a:
linea = 1;
while (fgets(buffer, 1001, fichero) != NULL)
   printf("Linea %d: \n\t%s", linea++, buffer);


* En el programa falta la declaración de la variable "linea".

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

Feynmann

Muchísimas gracias, con toda esta información me funciona la meta que tenia como programilla que quiero hacer, no lo he acabado aún pero quiza sigo posteando aqui dudas.

Muchas gracias de verdad, ;D

Pero una ultima cosa..
Dejo aqui el programa que estoy haciendo, es diferente de lo vuestro y me gustaria saber si no tiene ningun error garrafal que me de problemas más adelante.

Reto: Además estoy viendo que para 20k datos me tarda unos segundos, querria saber si hay alguna forma de acortar el tiempo de ejecución pues mis ficheros de datos tienen 200k datos y son muchos ficheros...

Pues dicho esto, os comento:
-El programa recibe un dichero datos.txt que es de una sola columna y que es de este tipo:
   611.1118
   611.6466
   612.8956
   611.8088
   615.3070
   614.8684
   ....ETC... (hasta 20K datos así)
-Este programa recoge este fichero, yo modifico (en este caso con una multiplicación) estos datos (pasandolos a int previamente)  y los multiplico por dos por ejemplo y luego volviendolos a convertir.
-Por ultimo recibo un fichero salida.txt como el siguiente:
1222.223600
1223.293200
1225.791200
1223.617600
1230.614000
1229.736800
1232.356000
...ETC...(Así hasta los 20k datos)


Mi codigo que funciona es este:
Código (cpp) [Seleccionar]

//programa para obtener archivos y modificarlos guardandolos en nuevos archivos.
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <fstream>

using namespace std;

// Funcion que hace algo
char nombre_fichero();

int main(){

   FILE *fichero;
FILE *fichero2;

  char nombre[11] = "datos.txt";
  char nombre2[11]= "salida.txt";
  char leer[1000];

  fichero = fopen( nombre, "r" );  // Fichero datos.txt desde el que leo los datos.
  fichero2= fopen( nombre2, "w");  // Fichero salida.txt donde escribire los datos.

if ( fichero == NULL ) {
     printf( "Fichero '%s' no se pudo abrir.\n", nombre ); /* error */
     return -1;
  }
  if ( fichero2 == NULL ) {
     printf( "Fichero '%s' no se pudo abrir.\n", nombre2 ); /* error */
     return -1;
  }

int i=0,n=20000;
double numero,numerof;

while(i<n) //detecta cuando acaba la informacion del fichero datos.txt
   {                                        
   fgets(leer,1000000,fichero); //lee una linea del fichero , la guarda en leer y pasa a la siguiente linea
numero = atof (leer);// convierto un char en un int
//Aqui hago las modificaciones
numerof =numero*2;
printf("%s %f \n", leer, numerof);
sprintf(leer, "%f\n",numerof);
// Escribo lo anterior al fichero2
   fputs(leer,fichero2);
i++;
   }
fclose(fichero);  //cierra fich datos.txt

getchar();
return 0;
}


Un saludete, a ver quien es el crack que me dice por donde van los tiros para acortarle tiempo! y Gracias!


EDITO: El programa lo necesitamos aqui en el departamento de electronica para hacer transformadas de fourier de señales, multiplicar por dos es una mera prueba para ver la conversión de datos.
Novato curioso, me gustaria aprender a programar bien en C/C++ por eso estoy aqui. Pero puedo echar una mano a cualquiera que me lo pida en temas de electronica!

amchacon

#19
He leído el código y no me he enterado de que iba, hasta que me he dado cuenta que estaba mal indentado:
Código (cpp) [Seleccionar]
while(i<n) //detecta cuando acaba la informacion del fichero datos.txt
  {                                        
fgets(leer,1000000,fichero); //lee una linea del fichero , la guarda en leer y pasa a la siguiente linea
numero = atof (leer);// convierto un char en un int
//Aqui hago las modificaciones
numerof =numero*2;
printf("%s %f \n", leer, numerof);
sprintf(leer, "%f\n",numerof);
// Escribo lo anterior al fichero2
  fputs(leer,fichero2);
i++;
  }


Debería ser:
Código (cpp) [Seleccionar]
while(i<n) //detecta cuando acaba la informacion del fichero datos.txt
{
   fgets(leer,1000000,fichero); //lee una linea del fichero , la guarda en leer y pasa a la siguiente linea
   numero = atof (leer);// convierto un char en un int
   
   //Aqui hago las modificaciones

   numerof =numero*2;
   printf("%s %f \n", leer, numerof);
   sprintf(leer, "%f\n",numerof);

   // Escribo lo anterior al fichero2

   fputs(leer,fichero2);
   i++;
}


Así se nota que esta en el bucle y no en el main.

Bueno ahora vamos a la eficiencia, lo primero:
Código (cpp) [Seleccionar]
printf("%s %f \n", leer, numerof);

Imprimir en pantalla supone una llamada al sistema y congelar el programa hasta que refresque la pantalla. No te lo recomiendo hacer printfs en un proceso que necesitas eficiencia.

Normalmente los contadores de progueso se hacen con un hilo de ejecución en paralelo, para no bloquear la tarea principal.

Pero viendo que estas empezando, no te voy a meter hilos. Sería mortal, en su lugar puedes hacer este "parche":
Código (cpp) [Seleccionar]

while(i<n) //detecta cuando acaba la informacion del fichero datos.txt
{
    fgets(leer,1000000,fichero); //lee una linea del fichero , la guarda en leer y pasa a la siguiente linea
    numero = atof (leer);// convierto un char en un int
   
    //Aqui hago las modificaciones

    numerof =numero*2;

    if (i%1000 == 0)
        printf("%s %f \n", leer, numerof);

    sprintf(leer, "%f\n",numerof);

    // Escribo lo anterior al fichero2

    fputs(leer,fichero2);
    i++;
}


De esa forma te escribe cada 1.000 palabras, asi no pierdes tanto tiempo y sabes si sigue funcionando...

Sigamos mirando:
Código (cpp) [Seleccionar]
fgets(leer,1000000,fichero); //lee una linea del fichero , la guarda en leer y pasa a la siguiente linea

El tamaño del array tiene un tamaño de 1000, no puedes hacer que lea hasta 1000000 caracteres. O cambias el array o cambias el fgets.

Para leer infinitos caracteres se puede hacer en C++ con su getline + string. Pero si sabes que no van a ocupar más de un tamaño x, dejalo mejor asi. Es más eficiente.

Por cierto:
Código (cpp) [Seleccionar]
while(i<n)

No recomiendo esto para nada, es mejor controlar el bucle con fgets como dice Rir37 (él si que es experto ^^):
Código (cpp) [Seleccionar]
while (fgets(leer, 1000, fichero) != NULL)
Por favor, no me manden MP con dudas. Usen el foro, gracias.

¡Visita mi programa estrella!

Rar File Missing: Esteganografía en un Rar