Java - lectura y escritura de HashSet en ficheros

 
Vista:
Imágen de perfil de J.Manuel
Val: 27
Ha aumentado su posición en 4 puestos en Java (en relación al último mes)
Gráfica de Java

lectura y escritura de HashSet en ficheros

Publicado por J.Manuel (10 intervenciones) el 08/05/2021 12:07:09
Buenas, en el siguiente código estoy intentado mediante dos métodos escribir y leer clientes que almaceno en archivo, pero a pesar de que uso un HashSet lo clientes se me duplican. ¿Alguna idea de dónde está mi error?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public static void EscribirFichero(Cliente cl) {
 
    ObjectOutputStream objectOutput = null;
    ObjectInputStream objectInput = null;
    HashSet<Cliente> cliHS = new HashSet<Cliente>();
 
 
    try {
        if(FILE_NAME.exists()) {
            objectInput = new ObjectInputStream(new FileInputStream(FILE_NAME));
            cliHS = (HashSet<Cliente>) objectInput.readObject();
        }
 
        cliHS.add(cl);
 
        objectOutput = new ObjectOutputStream(new FileOutputStream(FILE_NAME)); /// true
        objectOutput.writeObject(cliHS);
 
        System.out.println("Se ha generado el fichero " + FILE_NAME);
 
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } finally {
        if (objectOutput != null) {
            try {
                objectOutput.close();
            } catch (IOException ignored) {
            }
        }
    }
}
 
public static void LeerFichero() {
    ObjectInputStream objectInput = null;
 
    try {
        objectInput = new ObjectInputStream(new FileInputStream(FILE_NAME));
 
        Object actual = null;
        HashSet<Cliente> cliHS = null;
        while((actual = objectInput.readObject()) != null) {
            cliHS = (HashSet<Cliente>) actual;
            Iterator it = cliHS.iterator();
            while(it.hasNext()) {
                System.out.println("Datos cliente: "+it.next());
            }
 
        }
 
        objectInput.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch(EOFException e) {
 
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } finally {
        if (objectInput != null) {
            try {
                objectInput.close();
            } catch (IOException ignored) {
            }
        }
    }
}
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder
Imágen de perfil de Billy Joel
Val: 2.665
Oro
Ha mantenido su posición en Java (en relación al último mes)
Gráfica de Java

lectura y escritura de HashSet en ficheros

Publicado por Billy Joel (874 intervenciones) el 12/05/2021 23:19:16
Tengo una sospecha del error, pero podrías subir el archivo que lees; solo para salir de la sospecha
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
Imágen de perfil de J.Manuel
Val: 27
Ha aumentado su posición en 4 puestos en Java (en relación al último mes)
Gráfica de Java

lectura y escritura de HashSet en ficheros

Publicado por J.Manuel (10 intervenciones) el 13/05/2021 00:00:56
Gracias por su respuesta.

Adjunto comprimido el archivo generado. No tengo inconveniente en enviar todo el código.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
Imágen de perfil de Billy Joel
Val: 2.665
Oro
Ha mantenido su posición en Java (en relación al último mes)
Gráfica de Java

lectura y escritura de HashSet en ficheros

Publicado por Billy Joel (874 intervenciones) el 13/05/2021 00:16:10
wow casi me explota la cabeza.
Estas escribiendo un objeto en un archivo?
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
Imágen de perfil de J.Manuel
Val: 27
Ha aumentado su posición en 4 puestos en Java (en relación al último mes)
Gráfica de Java

lectura y escritura de HashSet en ficheros

Publicado por J.Manuel (10 intervenciones) el 13/05/2021 09:26:08
Así es, más bien una estructura de objetos Cliente que no se repitan.

Subo todo el código por si alguien quiere probarlo completo. Es un buen compendio de iniciación en Java, los métodos de escritura y lectura están en la clase GestionPedidos, a partir de la línea 392.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
Imágen de perfil de J.Manuel
Val: 27
Ha aumentado su posición en 4 puestos en Java (en relación al último mes)
Gráfica de Java

lectura y escritura de HashSet en ficheros

Publicado por J.Manuel (10 intervenciones) el 13/05/2021 18:00:47
Bueno, pues después de haberlo intentado de formas alternativas sigo llegando al mismo resultado por lo que creo, según la respuesta de otro usuario, que está pasando lo siguiente:

"Un HashSet utiliza el hashCode del objeto que pongas dentro, no el comparador.
Si no lo has modificado estará usando la posición de memoria como identificador.
Cuando añades un cliente lees primero el HashSet serializado anteriormente, creando objetos cliente en ciertas posiciones de memoria. Si el cliente que estas añadiendo ya existe, el HashSet no podrá saberlo porque estarán en distintas posiciones de memoria.
Es decir son dos objetos distintos aunque contengan exactamente los mismos datos."

No entiendo todavía muy bien por qué ocurre esto, ya que uso en el mismo programa los hashset sin este inconveniente.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
Imágen de perfil de Billy Joel
Val: 2.665
Oro
Ha mantenido su posición en Java (en relación al último mes)
Gráfica de Java

lectura y escritura de HashSet en ficheros

Publicado por Billy Joel (874 intervenciones) el 13/05/2021 18:04:39
¿Que tal si guardas los datos en lugar de los objetos?
¿Te serviría?
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar
Imágen de perfil de J.Manuel
Val: 27
Ha aumentado su posición en 4 puestos en Java (en relación al último mes)
Gráfica de Java

lectura y escritura de HashSet en ficheros

Publicado por J.Manuel (10 intervenciones) el 13/05/2021 18:07:09
Por supuesto, mientras se consiga el resultado esperado y no sea muy ineficiente. ¿Te estás refiendo a "trocear" mediante Strings?
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
Imágen de perfil de Billy Joel
Val: 2.665
Oro
Ha mantenido su posición en Java (en relación al último mes)
Gráfica de Java

lectura y escritura de HashSet en ficheros

Publicado por Billy Joel (874 intervenciones) el 13/05/2021 18:27:51
Los datos los puedes separar por tabs (\t), punto y comas (;)
Ejemplo:
1
Billy;Johnson;+50765616989;Panama

Lees el archivo línea a línea y separas los datos con un split(";");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public HashSet<Cliente> cargarClientes() {
    File archivo;
    FileReader fr = null;
    BufferedReader br;
    HashSet<Cliente> clientes = new HashSet();
    try {
        archivo = new File(FILE_NAME);
        fr = new FileReader(archivo);
        br = new BufferedReader(fr);
        String linea;
        while ((linea = br.readLine()) != null) {
            try {
                String[] d = linea.split(";");
                clientes.add(new Cliente(d[0], d[1], d[2], d[3], d[4]));
            } catch (Exception ex) {
                ex.printStackTrace(System.out);
            }
        }
    } catch (IOException e) {
        e.printStackTrace(System.out);
    } finally {
        try {
            if (fr != null) {
                fr.close();
            }
        } catch (IOException e2) {
            e2.printStackTrace(System.out);
        }
    }
    return clientes;
}

Saludos,
Billy Joel
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
2
Comentar
Imágen de perfil de J.Manuel
Val: 27
Ha aumentado su posición en 4 puestos en Java (en relación al último mes)
Gráfica de Java

lectura y escritura de HashSet en ficheros

Publicado por J.Manuel (10 intervenciones) el 13/05/2021 21:42:32
Hola Billy,

Muchas gracias por la respuesta! Había pensado también es prescindir del ObjectOutpuStream. Me ha sido de mucha utilidad.

Un saludo
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

lectura y escritura de HashSet en ficheros

Publicado por Tom (1831 intervenciones) el 13/05/2021 18:42:12
Yo creo que leyendo la doc te aclararías mejor. En mi opinión tu problema está en el (mal)uso que haces de los ObjectInputStream y ObjectInputStream (tampoco te has leído como funcionan, creo yo).

Copio y pego de la documentación de Set<T>:

"A collection that contains no duplicate elements. More formally, sets contain no pair of elements e1 and e2 such that e1.equals(e2), and at most one null element "

Y de HashSet<T>
"This class implements the Set interface"

Puedo estar equivocado pero yo deduzco de esto que si tus objetos no tienen sobreescrito equals() ... funciona tal y como dice en la doc de Object.equals:

"this method returns true if and only if x and y refer to the same object (x == y has the value true). "

Total, que si haces esto:

Persona yo = new Persona("Tom");
Persona el = new Persona("Tom");

(yo == el) es false, así que puedes añadir ambos objetos a un Set.

Por supuesto, para el uso de Collections (Map, Set, HashMap) la práctica correcta es sobreescribir tanto equals() como hashCode() (si es que lo necesitas que, generalmente, es que no).

Además, si te hubieras informado sobre ObjectInputStream ... habrías leído algo como que se crean nuevas referencias a los objetos referenciados desde el objeto que lees ...
Es más que probable que cada vez que haces una lectura estés duplicando lo que ya tienes (no he mirado todo tu código).

Yo seguiría lo que te han recomendado (sobreescribir equals y hashCode en tus clases) y revisar lo que haces cuando lees y escribes en los ficheros.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar
Imágen de perfil de J.Manuel
Val: 27
Ha aumentado su posición en 4 puestos en Java (en relación al último mes)
Gráfica de Java

lectura y escritura de HashSet en ficheros

Publicado por J.Manuel (10 intervenciones) el 13/05/2021 21:53:56
Hola Tom,

Gracias por tu respuesta.

Sobre ObjectOutputStream y HashSet sólo he leído la documentación que mi profesor me ha proporcionado, ya que estamos en un nivel principiante y si utilizo técnicas no descritas en dicha documentación o que son más avanzadas podrían darme por inválida la prueba práctica. No obstante, debería acostumbrarme a recurrir como bien haces tú a los docs.

Tendré que darle un enfoque similiar al que me ha dado Billy en el post anterior, aunque honestamente creo que si estoy tratando con objetos, lo suyo sería usar Object Output/Input Stream y darle el enfoque que mencionas de sobreescribir equals y hashcode.

Un saludo.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
Imágen de perfil de J.Manuel
Val: 27
Ha aumentado su posición en 4 puestos en Java (en relación al último mes)
Gráfica de Java

lectura y escritura de HashSet en ficheros

Publicado por J.Manuel (10 intervenciones) el 13/05/2021 23:30:54
Aquí pongo cómo me ha quedado funcionando, aunque poco eficiente, ya que almaceno información redundante pese a imprimir el objetivo deseado:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public static void EscribirFichero(Cliente cl) throws IOException {
 
    BufferedWriter bw = new BufferedWriter(new FileWriter(FILE_NAME,true));
    bw.write(cl.nombre+" "+cl.apellidos);
    bw.newLine();
    bw.flush();
 
}
 
 
public static void LeerFichero() throws IOException {
 
    BufferedReader br = new BufferedReader(new FileReader(FILE_NAME));
    String linea=br.readLine();
 
    ArrayList<String> alClientes = new ArrayList<String>();
    HashSet<String> hsClientes = new HashSet<String>();
 
    while(linea!=null){
        alClientes.add(linea);
        linea=br.readLine();
    }
 
    hsClientes.addAll(alClientes);
 
    Iterator i = hsClientes.iterator();
    while(i.hasNext()) {
        System.out.println("Cliente: "+i.next());
    }
 
}
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
Imágen de perfil de J.Manuel
Val: 27
Ha aumentado su posición en 4 puestos en Java (en relación al último mes)
Gráfica de Java

lectura y escritura de HashSet en ficheros

Publicado por J.Manuel (10 intervenciones) el 15/05/2021 12:24:50
Buenas, dejo resuelto el problema de forma diferente, mediante la sobreescritura de HashCode:

En la clase Cliente:

1
2
3
4
@Override
public int hashCode() {
    return (nombre + apellidos).hashCode();
}


En el main:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
public static void EscribirFichero(String nom,String ape) throws IOException {
 
    ObjectOutputStream objectOutput = null;
    ObjectInputStream objectInput = null;
    String cl;
    cl = nom+" "+ape;
 
    try {
        if(FILE_NAME.exists()) {
            objectInput = new ObjectInputStream(new FileInputStream(FILE_NAME));
            clientesHS = (HashSet<String>) objectInput.readObject();
        }
 
        clientesHS.add(cl);
 
        objectOutput = new ObjectOutputStream(new FileOutputStream(FILE_NAME));
        objectOutput.writeObject(clientesHS);
 
        System.out.println("Se ha generado el fichero " + FILE_NAME);
 
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } finally {
        if (objectOutput != null) {
            try {
                objectOutput.close();
            } catch (IOException ignored) {
            }
        }
    }
 
}
 
 
public static void LeerFichero() throws FileNotFoundException,IOException {
 
     HashSet<String> cliHS = new HashSet<String>();
 
    FileInputStream fis = null;
    ObjectInputStream ois = null;
    try {
        fis = new FileInputStream(FILE_NAME);
        ois = new ObjectInputStream(fis);
 
        while(true) {
            cliHS = (HashSet<String>)ois.readObject();
        }
 
    }catch(EOFException e) {
        System.out.println("Se han leido todos los registros");
    }catch(ClassNotFoundException e) {
        e.printStackTrace();
    }finally {
        if(ois!=null) {
            ois.close();
            fis.close();
        }
    }
 
    Iterator it = cliHS.iterator();
    while(it.hasNext()) {
        System.out.println("Cliente: "+it.next());
    }
}
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar