Foros del Web » Programación para mayores de 30 ;) » Java »

Más problemas con archivos

Estas en el tema de Más problemas con archivos en el foro de Java en Foros del Web. Hola: Estoy trabajando en un agenda, por el momento muy sencilla. Pare ello tengo además del main otras tres Clases, que son Menu, Persona, y ...
  #1 (permalink)  
Antiguo 21/08/2006, 10:09
 
Fecha de Ingreso: agosto-2006
Mensajes: 159
Antigüedad: 17 años, 8 meses
Puntos: 4
Más problemas con archivos

Hola:

Estoy trabajando en un agenda, por el momento muy sencilla.

Pare ello tengo además del main otras tres Clases, que son Menu, Persona, y Contactos.

La Clase Contactos es la que contiene un Vector de Personas, y Persona contiene un Hashtable con los datos de los contactos añadidos( nombre, teléfono etc...), además de un toString() sobreescrito.

El problema que tengo es que a la hora de salvar los datos de Persona al disco, lo hace en un archivo de texto que en llugar de respestar el salto de línea "\n" o el salto de carro "\r" o los dos al mismo tiempo lo que hace es escribir [], con lo que no puedo leer ese fichero correctamente para la persistencia de datos.

Para la escritura utilicé:
Código:
    public boolean salvarDatos(){
        boolean b = false;
        Object [] oa = new Object[this.getV().size()];
        Persona [] pa = new Persona[oa.length];
        this.getV().copyInto(oa);
        try{
            PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter("C:\\guardados.txt")));
            for(int i=0;i<oa.length;i++){
                pa[i] = (Persona) oa[i];
                pw.print(pa[i].toString()+"\r\n");
            }
            pw.close();
            b = true;
        }catch(IOException ioe){};
        return b;
    }
En la Clase Persona el método toString():
Código:
    public String toString(){
        String a = "Nombre:\n"+this.getHs().get("nombre")+"\n"
        +"Apellidos:\n"+this.getHs().get("apellido 1")+" "+this.getHs().get("apellido 2")+"\n"
        +"Localidad:\n"+this.getHs().get("localidad")+"\n"
        +"Provincia:\n"+this.getHs().get("provincia")+"\n"
        +"Pais:\n"+this.getHs().get("pais")+"\n"
        +"Dirección:\n"+this.getHs().get("tipo via")+" "+this.getHs().get("nombre via")+" "+this.getHs().get("numero via")+" "+this.getHs().get("piso via")+"\n"
        +"Teléfono fijo:\n"+this.getHs().get("teléfono fijo")+"\n"
        +"Teléfono móvli:\n"+this.getHs().get("teléfono móvil")+"\n"
        +"Otro número de contacto:\n"+this.getHs().get("otro número de contacto");
        return a.toUpperCase();
    }
Alguna orientación por favor.

Gracias.
  #2 (permalink)  
Antiguo 21/08/2006, 15:21
 
Fecha de Ingreso: febrero-2006
Mensajes: 20
Antigüedad: 18 años, 2 meses
Puntos: 0
prueba hber con pw.println ,aunque poniendo \r\n te debería dejar.

suerto
  #3 (permalink)  
Antiguo 22/08/2006, 09:46
 
Fecha de Ingreso: agosto-2006
Mensajes: 159
Antigüedad: 17 años, 8 meses
Puntos: 4
Hola:

Gracias por responder pero no funciona ni con println(), ni con print() ni con write().

Necesito un cable por favor.
  #4 (permalink)  
Antiguo 23/08/2006, 00:30
 
Fecha de Ingreso: octubre-2003
Mensajes: 3.578
Antigüedad: 20 años, 6 meses
Puntos: 51
¿No sería más sencillo utilizar una forma más directa de persistencia? A no ser que el formato tenga que ser obligatoriamente ese, por razones de comunicación con otras aplicaciones por ejemplo, sería más natural usar una BDD embebida, o incluso escribir en el fichero usando un ObjectOutputStream.

Otra pregunta es, ¿los atributos de persona van a a modificarse mucho (en el sentido de añadir atributos nuevos)? ¿Realmente necesitas meterlos en una Hashtable en vez de ponerlos directamente como atributos de Persona? Curiosidad más que nada por conocer las razones para hacer algo así.

Un saludo

PD: Respecto al problema original, Println se supone que deberia funcionar y escribirte los saltos de linea correspondientes al S.O. donde se ejecute el programa. :-?
  #5 (permalink)  
Antiguo 23/08/2006, 12:21
 
Fecha de Ingreso: agosto-2006
Mensajes: 159
Antigüedad: 17 años, 8 meses
Puntos: 4
Hola:

Gracias por responder.

Efectivamente existen muchas formas para una persistencia de datos, las conozco, aunque aún no las domino pues estoy aprendiendo Java.

Ahora estamos con los Arrays y los Vectores, y tenemos que desarrollar una pequeña agenda, nada profesional.

Por lo que sé sería mucho más fácil serializar un Objeto, pero ya digo que eso será en la versión 4 ó 5 de ésta agenda.

En el ejercicio nos piden manejo de collecciones y persistencia de datos. Ésta última la vimos muy por encima, así que por el momento sólo se escribir en un archivo y mal encima.

Reescribiré algunas cosas para ver si puedo conseguir escribir correctamente.

Si no estaré por aquí dando la lata.

Gracias.
  #6 (permalink)  
Antiguo 23/08/2006, 15:21
 
Fecha de Ingreso: octubre-2003
Mensajes: 3.578
Antigüedad: 20 años, 6 meses
Puntos: 51
Ah, comprendo. Me parece bien que empeceis por lo básico y así poco a poco la cosa queda con una base más sólida.

Respecto al código que pones, supongo que algunas cosas te habrán venido "dictadas" y como son ejemplos, a veces los detalles no se tienen en cuenta; pero por si acaso algunos comentarios.

.- Como ya mencioné lo normal es que "nombre", "apellido" etc fueran atributos de la clase Persona, y no valores dentro de un Hashtable.
.- En todo caso, si usarás una Hashtable para almacenar los atributos, por lo de usar collections supongo, lo normal sería usar la clase Map (de hecho una interfaz) para poder cambiar la implementación de forma más fácil. Quizá esto sea para el próximo tema .
.- No entiendo la parte de código en que copias del array de Persona al array de Objeto ya que no parece tener ninguna utilidad.
.- En el programa haces mucho uso de la concatenacion de cadenas con "+". Todavía no te lo habran enseñado pero es mucho más eficiente usar StringBuffer para eso para no consumir memoria con objetos de vida corta.
.- El tratamiento de excepciones que haces cuando abres el fichero y escribes en el no es del todo "correcto", puesto que una excepción podria dejarte el fichero abierto y ademas no estas tratando para nada las excepciones (eso puede ser cosa del copy/paste). Es bueno aprender la filosofia del tratamiento de excepciones cuanto antes para coger el "vicio" que toca. Si no te lo han mostrado ya, te lo pongo mañana que se me hace tarde .

No son comentarios para fastidiar sino con intención didáctica, espero que no te molesten.
Saludos
  #7 (permalink)  
Antiguo 24/08/2006, 14:22
 
Fecha de Ingreso: agosto-2006
Mensajes: 159
Antigüedad: 17 años, 8 meses
Puntos: 4
Hola:

Para nada me molestan los comentarios siempre y cuando no sean gratuitos, es decir que si son constructivos , como entiendo es el caso, son de agradecer.

Estoy reescribiendo bastante el ejercicio, pronto comento algo más.


Gracias una vez más.
  #8 (permalink)  
Antiguo 24/08/2006, 16:11
 
Fecha de Ingreso: agosto-2006
Mensajes: 159
Antigüedad: 17 años, 8 meses
Puntos: 4
Hola:

Aquí voy de nuevo.

La Clase Persona tiene esto:
Código:
public class Persona {
    private String nombre,apellido_1,apellido_2,localidad,provincia,pais,tipo_via,nombre_via,num_via,piso_via,tel_1,tel_2;
    public Persona(String [] a) {
        this.setNombre(a[0]);
        this.setApellido_1(a[1]);
        this.setApellido_2(a[2]);
        this.setTipo_via(a[3]);
        this.setNombre_via(a[4]);
        this.setNum_via(a[5]);
        this.setPiso_via(a[6]);
        this.setLocalidad(a[7]);
        this.setProvincia(a[8]);
        this.setPais(a[9]);
        this.setTel_1(a[10]);
        this.setTel_2(a[11]);
    }
    public String toString(){
        return (this.getNombre()+","+this.getApellido_1()+","+this.getApellido_2()+","+this.getTipo_via()+
                ","+this.getNombre_via()+","+this.getNum_via()+","+this.getPiso_via()+","+this.getLocalidad()+
                ","+this.getProvincia()+","+this.getPais()+","+this.getTel_1()+","+this.getTel_2()).toUpperCase();
    }
    public boolean compareTo(Object obj){
        boolean b = false;
        if(obj instanceof Persona){
            Persona p = (Persona) obj;
            if(p.hashCode() == this.hashCode()) b = true;
        }
        return b;
    }
Con sus getters y setters correspondientes. Más adelante corregiré las concatenaciones.

En la Clase Contactos:
Código:
import java.util.*;
import java.io.*;
public class Contactos{
    private Vector v;
    private File f;
    private PrintWriter pw;
    public Contactos() {
        this.setV(new Vector(20,5));
        try{
            this.setF(new File("C:\\guardar.txt"));
            this.setPw(new PrintWriter(new BufferedWriter(new FileWriter(f))));
        }catch(IOException ioe){
            System.out.println("No se puede acceder al Disco.");
            ioe.printStackTrace();
            System.exit(0);
        }finally{
            pw.close();
        };
    }   
    public boolean guardarContacto(String a){
        this.getV().add(new Persona(a.split(",")));
        return this.comprobarPersona(new Persona(a.split(",")));
    }
    public boolean comprobarPersona(Persona p){
        return this.getV().contains(p);
    } 
    public String [] listarContactos(){
        Object [] oa = new Object[this.getV().size()];
        String [] str = new String [oa.length];
        this.getV().copyInto(oa);
        for(int i = 0;i<oa.length;i++){
            Persona p = (Persona) oa[i];
            str [i] = p.toString();
        }
        return str;
    }
    public boolean salvarDisco(){
            String [] a = this.listarContactos();
            for(int i=0;i<a.length;i++){
                String [] b = a[i].split(",");
                for(int j=0;j<b.length;j++){
                    this.getPw().print(b[j]+"\r\n");
                }
            }
            this.getPw().flush();
            this.getPw().close();
            return this.getF().exists();
    }
}
También con sus getters y setters.

Ahora simplemente crea el archivo pero no escribe nada en él.

Por hoy ya lo dejo que estoy harto de darle a la tecla, pero si lees esto por favor hazle un huequito para orientarme algo.

Muchas gracias.
  #9 (permalink)  
Antiguo 25/08/2006, 08:13
 
Fecha de Ingreso: octubre-2003
Mensajes: 3.578
Antigüedad: 20 años, 6 meses
Puntos: 51
Hola,
Clase Persona:
.- El constructor con un array no es buena idea, ya que entonces deberias comprobar la longitud que tiene, etc etc. Así como está, si pasas un array incorrecto te dara un error en tiempo de ejecución, de la otra forma estos errores se detectan en tiempo de compilación y eso es muy importante para hacer programas sólidos.
.- El metodo compareTo() que has implementado es exactamente la misma implementación que hace equals de la clase Object, así que no sirve de mucho. Normalmente el método equals (y compareTo) deberia tener un sentido lógico, si te hace falta, como que dos Persona son iguales si el nombre y los dos apellidos son el mismo, por ejemplo. Además de eso, hay que implementar el metodo hashCode para que sea coherente con esa estrategia. Si no, dos objetos con exactamente los mismos Strings pueden ser introducidos en el vector ya que exists() devolvera false aunque todos los datos sean iguales.

Contactos:
.- El tratamiento de ficheros deberias hacerlo en cada metodo, ya que guardar el fichero en si de una llamada a otra de un metodo no suele ser buena idea. Y mantener un fichero o Stream abierto a lo largo de varias llamadas y cerrarlo con otra llamada no es buena idea casi nunca.
.- A la hora de listar los contactos no hace falta copiar un vector en un array para recorrerlo. Vector, o cualquier otra coleccion, tiene metodos para recorrer todos sus elementos sin tener que hacer una copia en un array.
.- El tratamiento de errores no es "completo". Con esto quiero decir que hay errores que no se detectan que te causaran otros errores posteriores, errores que no se capturan y que haran saltar el programa etc. Lo mejor es detectar los errores cuantos antes, tratarlos al nivel que toca y tenerlos en cuenta para que el programa no se rompa descontroladamente si no que al menos notifique los errores como toca antes de pararse.

En este caso solo tratas un error, una IOException al intentar abrir el fichero, y en caso de que ocurra sales del programa. En algunos programas no podrás salir sin más, así que es mejor tratar el error, cerrar el PW si esta abierto etc etc. Ademas de que en el ultimo metodo, por ejemplo, no compila ya que no estas tratando las excepciones.

Poco a poco.

S!
  #10 (permalink)  
Antiguo 26/08/2006, 21:41
 
Fecha de Ingreso: agosto-2006
Mensajes: 159
Antigüedad: 17 años, 8 meses
Puntos: 4
Hola:

Bufff, cuantas cosas. Pero cambiévarias cosas como me comentas. Lo que aún no entiendo es lo del tratamiento de errores, vamos que no se a que te refieres.

Si yo estoy trabajando con el paquete "io" lo lógico sería poner un "IOException", por que si no encuentra el fichero, porque no existe, cuando yo quiera escribir lo crea automáticamente, o no?

¿Que otro método crees que debo poner para capturar los errores?

Y en cuanto a la lista de contactos esto estaría más correcto, verdad?
Código:
    public String [] listarContactos2(){
        String [] str = new String[this.getV().size()];
        for(int i=0;i<this.getV().size();i++){
            str[i] = ((Persona) this.getV().get(i)).toString();
        }
        return str;
    }
Gracias.
  #11 (permalink)  
Antiguo 28/08/2006, 02:05
 
Fecha de Ingreso: octubre-2003
Mensajes: 3.578
Antigüedad: 20 años, 6 meses
Puntos: 51
Para recorrer un Vector, lo puedes hacer directamente con un iterador, sin necesidad de copiar temporalmente a un array:
Código:
  public String[] listarContactos2()
  {
    String[] str = new String[this.getV().size()];
    int i = 0;
    // En Java5 podrías incluso usar el foreach
    for (Iterator iter = this.getV().iterator(); iter.hasNext();)
    {
      Persona unaPersona = (Persona) iter.next();
      str[i] = unaPersona.toString();
    }
    return str;
  }
Y para el tratamiento de errores, la cuestion sería algo como que no tienes que guardar los streams abiertos todo el rato y la cosa quedaria algo más así:
Código:
  private File f;
  private final String NOMBRE_FICHERO = "C:\\guardar.txt";
  public Contacto()
  {
    this.setF(new File(NOMBRE_FICHERO));
  }

  public boolean salvarDisco()
  {
    boolean salvadoCorrectamente = false;
    String[] a = this.listarContactos();
    PrintWriter thePW = null;
    FileWriter theFW = null;
    try
    {
      theFW = new FileWriter(this.getF());
      thePW = new PrintWriter(theFW);
      for (int i = 0; i < a.length; i++)
      {
        String[] b = a[i].split(",");
        for (int j = 0; j < b.length; j++)
        {
          thePW.print(b[j] + "\r\n");
        }
      }
      thePW.flush();
      salvadoCorrectamente = true;
    }
    catch (IOException e)
    {
      System.err.println("Ocurrió un error guardando los contactos: " + e.getMessage());
      e.printStackTrace();
    }
    finally
    {
      if(thePW!=null)
      {
        thePW.close();
      }
    }    
    return salvadoCorrectamente;
  }
Fijate que con el try/catch/finally, seguro que cierras siempre el Stream al fichero, aunque haya una excepcion. Y que detectas si todo fue bien al grabar, ya que solo será true si todo fue bien hasta el flush. Así en cada metodo que trata el fichero controlas los errores y puedes saber, en caso de error, donde y cuando pasó, aparte de minimizar el tener abiertos los ficheros que nunca es bueno más allá de lo necesario.

El bloque try/catch/finally así es típico de cualquier recurso que tengas que crear/obtener y luego devolver/cerrar de forma segura al 100%. (Streams, Conexiones a BDD...)

Un saludo.
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 11:52.