Como extraer datos de un txt y guardar en funcion de un valor en un binario??

Iniciado por valeeen, 27 Enero 2016, 15:47 PM

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

valeeen

Muy buenas amigos,
para un ejercicio me piden que lea un txt que tenga la siguiente estructura:

nombre # renta nota

a partir de este txt, tengo que filtrar por los que tengan una renta menor que x (por ejemplo 10.000) y solo esos guardarlos en un archivo binario.

De momento lo que tengo hecho es lo que veis abajo, lo unico que he conseguido es que si pongo un "cout" pinto todas las lineas del txt, pero no consigo filtrar por el segundo valor y meter todo lo que cuadre en un archivo binario...

En el código que tengo quería probar a sacar el único nombre que tenia con el valor 6.000 pero no lo hace...

me podeis ayudar?

gracias!!

archivo .h:

Código (cpp) [Seleccionar]


// main.h

#pragma once

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

#define MAX 50

typedef struct {
char nombre[MAX];
int renta;
float nota;
}lista;

int getLength(lista[]);


archivo cpp
Código (cpp) [Seleccionar]

#include "Header.h"

void main()
{


lista persona;
fstream archivo, archivodat;
archivo.open("solicitudes.txt", ios::in);
archivodat.open("aceptados.dat", ios::out | ios::binary);
if (!archivo) {
cout << "Error al leer archivo";
}
else {
if (!archivodat)
cout << "Error creando el archivo binario";
else {
archivo.getline(persona.nombre, MAX, '#');
archivo >> persona.renta, ' ';
if (persona.renta == '6000')
{
archivo >> persona.nota;
while (!archivo.eof()) {
archivo.getline(persona.nombre, MAX, '#');
archivo >> persona.renta, ' ';
archivo >> persona.nota;
archivodat.write(reinterpret_cast<const char *>(&persona), sizeof(lista));
}
archivodat.close();
}

}
archivo.close();
}

system("pause");
}

class_OpenGL

Si no he entendido mal, lo que quieres hacer es guardar la estructura 'persona' como binario en un archivo. La estructura es
Código (cpp) [Seleccionar]
typedef struct {
char nombre[MAX];
int renta;
float nota;
}lista;


Bien, si ese es el objetivo, hay un error. El problema es que cuando guardas la estructura en un archivo copiada de byte a byte, cuando copias la variable 'nombre', en realidad estás copiando la dirección de memoria donde reside el primer byte de la cadena.

Por ejemplo, declaro el siguiente objeto:

Código (cpp) [Seleccionar]
lista persona;

persona.nombre = "Esto es un nombre";
persona.renta = 14000;
persona.nota = 5;


Bien, ahora la estructura, a nivel de bits, se vería (por ejemplo), así:
0xF4567E22 // Dirección de memoria
0x000036B0 // 14000
0x00000005 // 5


Como ves, en ningún sitio aparece el nombre como tal. Entonces, lo que tendrías que hacer es primero hacer un "write" con la cadena del nombre, y luego tendrías que guardar tanto la renta como la nota en binario... Puedes usar el siguiente fragmento:

Código (cpp) [Seleccionar]
archivodat.write(persona.nombre, MAX);
archivodat.write(reinterpret_cast<const char*>(&persona.renta), sizeof(int) + sizeof(float));

Programador aficionado. Me quiero centrar en programar videojuegos. La API que uso para crearlos es OpenGL

valeeen

Gracias por la ayuda!

He introducido el código que me has dado y he comentado parte del que tenia, pero no consigo guardar en binario solo los que no superen X renta (en este caso he probado con 6000)

Código (cpp) [Seleccionar]

#include "Header.h"

void main()
{


lista persona;
fstream archivo, archivodat;
archivo.open("solicitudes.txt", ios::in);
archivodat.open("agenda.dat", ios::out | ios::binary);
if (!archivo) {
cout << "Error al leer archivo";
}
else {
if (!archivodat)
cout << "Error creando el archivo binario";
else {
archivo.getline(persona.nombre, MAX, '#');
archivo >> persona.renta, ' ';
if (persona.renta <= '6000')
{
//archivo >> persona.nota;
while (!archivo.eof()) {
//archivo.getline(persona.nombre, MAX, '#');
//archivo >> persona.renta, ' ';
//archivo >> persona.nota;
archivodat.write(persona.nombre, MAX);
archivodat.write(reinterpret_cast<const char*>(&persona.renta), sizeof(int) + sizeof(float));
//archivodat.write(reinterpret_cast<const char *>(&persona), sizeof(lista));
}
archivodat.close();
}

}
archivo.close();
}

system("pause");
}


En mi txt tengo:

Pepito Perez#5000 8.1
Pepa Gonzalez#6000 5.1
Kike Alvarez#7000 9.3

Entonces debería de guardar solo los dos primeros, pero no consigo que funcione, compila pero no hace su función...

¿Como puedo hacerlo?

Muchas gracias!

ivancea96

Las constantes numéricas no se ponen entre comillas:
Código (cpp) [Seleccionar]
persona.renta <= '6000'
->
Código (cpp) [Seleccionar]
persona.renta <= 6000

Dices que no hace su función. Pero decir eso es no decir nada. Qué es lo que hace y qué es lo que no hace. Si preguntas de nuevo, es obvio que no hace su función.

valeeen

Cierto, perdon jeje

Con este código ahora mismo lo que hace es leer pero nunca para, no se porque, pero se pone a escribir en binario y el archivo va creciendo pero sin sentido, solo deberia de escribir dos entradas y no para...

Código (cpp) [Seleccionar]

#include "Header.h"

void main()
{


lista persona;
fstream archivo, archivodat;
archivo.open("solicitudes.txt", ios::in);
archivodat.open("agenda.dat", ios::out | ios::binary);
if (!archivo) {
cout << "Error al leer archivo";
}
else {
if (!archivodat)
cout << "Error creando el archivo binario";
else {
archivo.getline(persona.nombre, MAX, '#');
archivo >> persona.renta, ' ';
if (persona.renta <= 6000)
{
//archivo >> persona.nota;
while (!archivo.eof()) {
//archivo.getline(persona.nombre, MAX, '#');
//archivo >> persona.renta, ' ';
//archivo >> persona.nota;
archivodat.write(persona.nombre, MAX);
archivodat.write(reinterpret_cast<const char*>(&persona.renta), sizeof(int) + sizeof(float));
//archivodat.write(reinterpret_cast<const char *>(&persona), sizeof(lista));
}
archivodat.close();
}

}
archivo.close();
}

system("pause");
}


No se que tengo mal (que seguro son muchas cosas)

Gracias por la ayuda

saludos

ivancea96

Código (cpp) [Seleccionar]
while (!archivo.eof()) {
Nunca lees de archivo. Así que nunca saldrá del whiile. Tendrás que descomentar las líneas donde lees, colocar otras, o colocar otra condición.

Carlos D. Alvarez

Cita de: class_OpenGL en 27 Enero 2016, 17:54 PM

Bien, ahora la estructura, a nivel de bits, se vería (por ejemplo), así:
0xF4567E22 // Dirección de memoria
0x000036B0 // 14000
0x00000005 // 5



Chicos, recuerden que si bien las cadenas de caracteres son en realidad punteros al primer caracter, cuando la cadena es estática, es almacenada en la propia estructura. En tal caso se guardaría en memoria  TAL CUAL. Si guardas la estructura, tambien se guarda la cadena, no el puntero.
Una organización y un fin

class_OpenGL

Cita de: Carlos D. AlvarezChicos, recuerden que si bien las cadenas de caracteres son en realidad punteros al primer caracter, cuando la cadena es estática, es almacenada en la propia estructura. En tal caso se guardaría en memoria  TAL CUAL. Si guardas la estructura, tambien se guarda la cadena, no el puntero.

Pues eso no lo sabía. Para probarlo, he elaborado el siguiente código:

Código (cpp) [Seleccionar]
#include <iostream>

struct FOO {
char lpszName[33];
};

int main() {
FOO foo = {"Esto es una cadena de caracteres"};

std::cout << "Size: " << sizeof(foo) << std::endl;

for(unsigned int i = 0; i < sizeof(foo); i++) {
std::cout << reinterpret_cast<char*>(&foo)[i];
}

std::cin.get();
return 0;
}


el cual imprime byte a byte toda la estructura... Lo que me ha sorprendido es obtener la siguiente salida:

Size: 33
Esto es una cadena de caracteres


Me ha sorprendido, porque no he declarado la cadena como estática, como mencionas en tu respuesta... Espero que alguien pueda aclararlo.

PD.: He usado el compilador de MinGW64 (el g++ de 64 bits para Windows).
Por si aclara algo, no he usado ninguna etiqueta al compilar (vamos, que no lo he compilado como c++11, ni nada parecido...)

Programador aficionado. Me quiero centrar en programar videojuegos. La API que uso para crearlos es OpenGL

ivancea96

Aclarado está. Como dijo Carlos, un array guarda los datos consecutivos en su memoria, en vez de guardar un puntero.

Como detalle, si inicializas un array con una constante como ahí has escrito, el compilador automáticamente copia los datos. Lo ves fácilmente si compilas el programa a ensamblador (opción -S con GCC).
La salida para:
Código (cpp) [Seleccionar]
int main(){
char array_var[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
}

En mi caso, fue esta (el trozo que afecta al array):
Código (asm) [Seleccionar]
movl $1145258561, 1(%esp)
movl $1212630597, 5(%esp)
movl $1280002633, 9(%esp)
movl $1347374669, 13(%esp)
movl $1414746705, 17(%esp)
movl $1482118741, 21(%esp)
movw $23129, 29(%esp)
movb $0, 31(%esp)


Ya para finalizar, ver que, la primera asignación: "1145258561". En Hexadecimal es 44434241. Separando, se ve lo evidente: 44 43 42 41, son los caracteres DCBA.
Los penúltimos, "23129", "5A59". Y por último, el caracter nulo.

Sin embargo, si declaramos array_var como const char*, obtendremos una salida así:

Código (asm) [Seleccionar]
LC0: .ascii "ABCDEFGHIJKLMNOPQRSTUVWXYZ\0"
movl $LC0, 12(%esp)


Como vemos, solo copia su dirección.

class_OpenGL

Interesante... ¡Cada día se aprende algo nuevo!
Por si no ha quedado claro, lo que ha dicho ivancea96 es que cuando declaramos un array dentro de una estructura (o clase), todos los datos de ese array estarán dentro de la misma (pero el array seguirá siendo un puntero, esto se explica mejor con ensamblador...), mientras que si declaramos un puntero como tal, entonces (evidentemente), los datos apuntados por ese puntero no estarán dentro de la estructura.

Programador aficionado. Me quiero centrar en programar videojuegos. La API que uso para crearlos es OpenGL