1. Este site usa cookies. Ao continuar a usar este site está a concordar com o nosso uso de cookies. Saber Mais.

JAVA - Gravar Objectos em Ficheiro, e carregar os Objectos do Ficheiro para ArrayList

Discussão em 'Programação' iniciada por Rexobias, 7 de Janeiro de 2009. (Respostas: 19; Visualizações: 5729)

  1. Rexobias

    Rexobias Power Member

    Malta, precisava de ajuda urgente aqui com um problema que me tem destruido a paciência. O programa é em Java e estou a usar o netbeans.

    Tenho umas textFields que correspondem a cada um dos campos de uma classe. O objecto é facilmente criado através de um método que é chamado no evento de um botão "Criar". Após criado o objecto, chamo o seguinte método para gravar o mesmo num ficheiro:

    Código:
            
    public void escrever(CartaoFuncionario func) throws FileNotFoundException, IOException {
            ObjectOutputStream file = new ObjectOutputStream((new FileOutputStream(ficheiroFunc, true)));
            ObjectOutputStream buffer = new ObjectOutputStream(file);
            try {
                buffer.writeObject(func);
     
            } catch (Exception e) {
     
                e.printStackTrace();
            } finally {
                buffer.close();
            }
        }
    
    Ao abrir o ficheiro criado (através do bloco de notas), noto que a informação é armazenada no mesmo sem problemas, como é pretendido.

    O meu próximo objectivo é ter um método que carregue o conteudo do ficheiro para um ArrayList do tipo dos objectos que foram guardados. Tenho o seguinte método, que infelizmente resulta em erros, ou seja, não consigo ler os objectos do ficheiro:

    Código:
        public void ler() throws IOException{
     
            ObjectInputStream ficheiro = new ObjectInputStream(
            new FileInputStream(ficheiroFunc));
     
            try {
                cartoesFunc.add((CartaoFuncionario) ficheiro.readObject());
            }
     
            catch (ClassNotFoundException ex){
     
            }
            ficheiro.close();
        }
    
    As varíáveis e afins estão todas bem declaradas, o problema está no código, muito provavelmente no método de leitura. Pensava que este pequeno objectivo fosse fácil de cumprir mas a verdade é que não tenho conseguido fazer o pretendido.

    Help meus caros Javáticos :sad:
     
  2. napalm

    napalm Power Member

    Suponho que estejas a chamar várias vezes o método de escrita. O problema pode estar no facto de estares a fazer append ao ficheiro quando o que devias estar a fazer é chamar várias vezes o writeObject da mesma ObjectOutputStream. E.g.
     
  3. Baderous

    Baderous Banido

    Que erros é que dá?
    Eu fiz assim e funcionou:
    Código:
    ArrayList<CartaoFuncionario> l = new ArrayList<CartaoFuncionario>();
    CartaoFuncionario c1 = null;
            ObjectInputStream ooin = null;
            try {
                ooin = new ObjectInputStream(new FileInputStream("ficheiro.obj"));
                c1 = (CartaoFuncionario) ooin.readObject();
                ooin.close();
            } catch (IOException e) { System.out.println(e.getMessage());}
            catch (ClassNotFoundException e) { System.out.println(e.getMessage()); }
            l.add(c1);
    Já agora, porque é que na escrita estás a abrir uma ObjectOutputStream sobre outra ObjectOutputStream? Pelo nome que deste à 2ª penso que querias um buffer, nesse caso seria BufferedOutputStream e nem precisavas de a declarar:

    Código:
    ObjectOutputStream file = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(ficheiroFunc, true)));
     
  4. nasic

    nasic Power Member

    Outra abordagem que poderias seguir, e até poderia facilitar a tua vida nalguns casos, seria gravar directamente no ficheiro o arraylist de "CartaoFuncionario". Assim bastaria ler e escrever uma vez. Atenção que neste caso, não deves fazer append ao ficheiro, mas sim escrever por cima do seu conteudo.

    Foi só uma sugestão:D
     
  5. Rexobias

    Rexobias Power Member

    Obrigado pessoal. nasic essa ideia passou-me pela cabeça, e realmente seria muito mais fácil (GUI -> Classes -> ArrayList -> Ficheiro) mas queria tornar o sistema mais eficaz gravando só o que é novo (claro que vai trazer-me dificuldades quando quiser eliminar registos, mas quando chegar a esse problem logo vejo).

    Bem, de qualquer maneira melhorei muito o código com a vossa ajuda, mas ainda tenho um só problema:

    método de escrita:
    Código:
        public void escrever(CartaoFuncionario func) throws FileNotFoundException, IOException {
            ObjectOutputStream ficheiro = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(ficheiroFunc, true)));
            
            try {
                ficheiro.writeObject(func);
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    ficheiro.close();
                }
        }  
    
    método de leitura:
    Código:
        public void ler() throws IOException{
            CartaoFuncionario cartao = null;
            ObjectInputStream entrada = null;
            try {
                ooin = new ObjectInputStream(new FileInputStream(ficheiroFunc));
                cartao = (CartaoFuncionario) entrada.readObject();
                entrada.close();
            } catch (IOException e) { System.out.println(e.getMessage());}
            catch (ClassNotFoundException e) { System.out.println(e.getMessage()); }
            cartoesFunc.add(c1);        
        }
    
    O meu problema é o seguinte. Eu faço a escrita de vários objectos (vamos supor Antonio, Maria e José (por esta ordem). Faço a escrita para o ficheiro chamando o método de escrita após criar cada objecto (carregar no botao "Criar"). Após criar os 3 objectos, tenho um outro botao que ao carregar nele, chama o método de leitura que devia preencher o ArrayList indicado com todos os 3 objectos anteriormente criados que estão armazenados no ficheiro, e depois chamo um outro metodo que imprime o conteudo do ArrayList.

    O problema é que só obtenho o António, o primeiro registo.

    Provavelmente preciso de um ciclo While no processo de leitura ... algo do género, enquanto tem registos/objectos no ficheiro vai fazendo o Add dos mesmos no ArrayList.

    Cumprimentos.
     
  6. nasic

    nasic Power Member

    Exactamente, só obtens o primeiro registo pq só lês esse.
    para leres todos faz algo do genero:
    Código:
    CartaoFuncionario obj = null;
     
    while ((obj = inputStream.readObject()) != null) {
           if (obj instanceof CartaoFuncionario )
                    array.add(obj);
    }
    
    Tive para te dizer isto no post anterior, mas assim aprendes mais:P

    Já agora "CartaoFuncionario" é serializable certo?
    Se isto for chinês é so procurar no google
     
    Última edição: 7 de Janeiro de 2009
  7. Rexobias

    Rexobias Power Member

    Sim, é tudo serializable, lol :P

    Obrigado ... vou ver se resulta.

    EDIT: Bem, o código parece-me correcto, mas continua a ler só o primeiro :S Aqui fica o código (sei que estou lá perto):

    Código:
        public void ler() throws IOException{
            CartaoFuncionario cartao = null;
            ObjectInputStream streamEntrada = null;
            try {
                streamEntrada = new ObjectInputStream(new FileInputStream(ficheiroFunc));
                while ((cartao = (CartaoFuncionario) streamEntrada.readObject()) != null) {
                    cartoesFunc.add(cartao); 
                }            
                streamEntrada.close();
            } catch (IOException e) { System.out.println(e.getMessage());}
            catch (ClassNotFoundException e) { System.out.println(e.getMessage()); }
        }
    
     
    Última edição: 7 de Janeiro de 2009
  8. nasic

    nasic Power Member

    Não será problema da escrita?
    Tenta abrir o ficheiro e procurar o que inseriste.és capaz de encontrar texto no meio do "lixo".
    Faz debug tb.
     
  9. Rexobias

    Rexobias Power Member

    Actualmente faço assim a escrita:

    Código:
        public void escrever(CartaoFuncionario func) throws FileNotFoundException, IOException {
            ObjectOutputStream ficheiro = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(ficheiroFunc, true)));
            
            try {
                ficheiro.writeObject(func);
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    ficheiro.close();
                }
        }   
    
    Já abri o ficheiro e aparecem blocos de texto. No 1º parece indicar a forma como a classe é construida, nos restantes dá para ver a informaçao dos objectos adicionados - aquilo tem uns gatafunhos misturados.

    :S
     
  10. napalm

    napalm Power Member

    Mas assim só estás a escrever um objecto??? E esse append ao ficheiro vai dar maravilha...
    Mostra o código que invoca a função escrever.
     
  11. Rexobias

    Rexobias Power Member

    Indo por partes.

    1-Tenho um formulário em ambiente gráfico com Textfields. Através dos getText() das TextFields obtenho os campos que formam a classe. O objecto é criado e guarda os valores enviados.

    2-O formulário tem um botão criar que ao ser carregado, chama um evento que consiste em criar o objecto e preencher os campos da mesma com o conteudo das TextFields.

    3-Assim que criamos esse objecto ele é enviado para o ficheiro, e guardado no mesmo - por isso uso o append, para ir guardando registos á medida que são criados.

    4-Por fim, chamo o método de leitura que retira a informação do ficheiro e guarda o mesmo num ArrayList de Objectos (do tipo que foi guardado anteriormente). Depois tenho um método para testar a leitura do ficheiro que consiste em imprimir o conteudo do ArrayList.

    Aqui fica a forma como chamo o método escrever:

    Código:
    listaFunc.escrever();
    
    listaFunc é um objecto de uma classe que tem como campo o tal ArrayList de objectos e os métodos de escrita e leitura no ficheiro.
     
  12. joao.miguel

    joao.miguel Power Member

    Uma pequena recomendação:
    Se é só os dados que queres guardar, devias optar por serializar isso tudo para XML (e vice-versa). Futuramente se mudares o objecto, não vais ter problemas de leitura porque os objectos depois são diferentes e não vais consegues fazer um cast.
     
  13. Baderous

    Baderous Banido

    A resposta para a tua dúvida é a seguinte: Não podes fazer append! Tens de arranjar outra solução. Talvez a solução do nasic de usar um ArrayList.
    http://www.velocityreviews.com/forums/t147205-problem-appending-objects-to-file.html
    http://mindprod.com/jgloss/runerrormessages.html#STREAMCORRUPTEDEXCEPTION
    http://mindprod.com/jgloss/gotchas.html#SERIALIZATION
     
  14. Rexobias

    Rexobias Power Member

    Bem, depois de tudo mudei de ideias e vou alterar o esquema do programa, pois não posso perder mais tempo, e estou totalmente dependente deste processo de escrita e leitura para poder terminar o mesmo. Cada vez que crio um registo, adiciono o mesmo ao ArrayList, e guardo o ArrayList num ficheiro. Esquematizando o que estou a pensar:

    Abrir Programa:
    -Carrega conteudo do Ficheiro para o ArrayList cartoesFunc;

    Adicionar novo Cartao:
    -Utilizador introduz informação nas TextFields;
    -O conteudo é enviado para os campos da classe;
    -Adiciona objecto ao ArrayList;
    -Grava conteudo do ArrayList no ficheiro;

    Esta é a minha ideia, mas ainda estou com problemas, muito provavelmente no processo de escrita e de leitura. Ao escrever vários registos o ficheiro parece manter sempre o seu tamanho. Depois de editar o mesmo noto que apenas o ultimo registo se encontra no mesmo. Ao ler e imprimir o conteudo do ficheiro para um ArrayList, e ao imprimir o tal ArrayList obtenho só o ultimo registo.

    Aqui ficam os métodos de escrita e de leitura (cartoesFunc é o meu ArrayList, e CartaoFuncionario a classe dos objectos guardados no ArrayList) :

    Código:
        public void escrever() throws Exception{   
            ObjectOutputStream saida = new ObjectOutputStream(new FileOutputStream("CartoesFunc.dat"));   
            saida.writeObject(cartoesFunc);   
            saida.close();
        }      
    
    Código:
        public void ler() throws Exception{   
            ObjectInputStream entrada = new ObjectInputStream(new FileInputStream("CartoesFunc.dat"));    
            cartoesFunc = (ArrayList<CartaoFuncionario>)entrada.readObject();
            entrada.close();        
        } 
    
     
    Última edição: 8 de Janeiro de 2009
  15. ora se queres ler e escrever para um ficheiro... nao queres usar bds digo eu... o serializable tb nao te serve... já pensaste em usar xml e schemas? :) com jaxb já tinhas isso feito https://jaxb.dev.java.net
    ou entao estavas a por duvidas sobre isso agora :lol:
     
  16. Baderous

    Baderous Banido

    Podes forçar o flush da stream de output fazendo:
    Código:
    saida.flush();
    Mas mesmo assim, não creio que vá resolver o problema. Esse código está a gerar warnings devido ao uso de operações inseguras, ou seja, aquele casting do Object para ArrayList<CartaoFuncionario> é inseguro porque isso não é um tipo genérico, é um tipo parametrizado. O melhor será criares uma classe ListaFuncionarios que tem como variável de instância um ArrayList<CartaoFuncionario> e codificas nessa classe os métodos para adicionar, remover, escrever em ficheiro, etc e depois, na classe onde escreves e lês, crias uma instância de ListaFuncionarios à qual adicionas os funcionários, bastando-te depois gravar essa instância na escrita, e ler essa instância na leitura (fazendo o casting para ListaFuncionarios).
     
  17. napalm

    napalm Power Member

    o "over engineering" é forte neste...
     
  18. nasic

    nasic Power Member

    Reparei agora num promenor que pode fazer falta.
    Não tas a fechar o FileOutputStream...
    @Baderous:
    Podes fazer append sim...eu já utilizei esse método e funcionou perfeitamente.
    @Rexobias:
    Fui buscar código que escrevi há uns tempos para recordar, e tenho isto feito da seguinte forma:
    para escrever:
    Para ler:
    Outro problema que podes ter aí,é a forma como lês até ao fim do ficheiro. Ontem se calhar não te dei o melhor conselho. Desculpa lá.
    Como te disseram usa smp, que necessário, o flush antes de fechares as streams.
    Como te disse ontem, faz debug nisso e depuração do teu codigo, atraves duns sops dão, smp muito jeito.
    É fundamental perceberes se o problema está na escrita ou na leitura do ficheiro.
     
    Última edição: 8 de Janeiro de 2009
  19. napalm

    napalm Power Member

    O fluxo do teu código deve ser algo tipo isto:
    Código:
    package bolos;
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;
    import java.util.ArrayList;
    import java.util.List;
    
    public class SerializeTest {
    
        public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
            new SerializeTest();
    
        }
    
        @SuppressWarnings("unchecked")
        public SerializeTest() throws FileNotFoundException, IOException, ClassNotFoundException {
            
            List<Bolos> lst = new ArrayList<Bolos>();
            ObjectOutputStream oos;
            
            lst.add(new Bolos(1));
            oos = new ObjectOutputStream(new FileOutputStream("bolos"));
            oos.writeObject(lst);
            oos.close();
            lst.add(new Bolos(2));
            oos = new ObjectOutputStream(new FileOutputStream("bolos"));
            oos.writeObject(lst);
            oos.close();
            lst.add(new Bolos(3));
            oos = new ObjectOutputStream(new FileOutputStream("bolos"));
            oos.writeObject(lst);
            oos.close();
            lst.add(new Bolos(4));
            oos = new ObjectOutputStream(new FileOutputStream("bolos"));
            oos.writeObject(lst);
            oos.close();
            lst.add(new Bolos(5));
            oos = new ObjectOutputStream(new FileOutputStream("bolos"));
            oos.writeObject(lst);
            oos.close();
            
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("bolos"));
            lst = (List<Bolos>) ois.readObject();
            for(Bolos bolos: lst) {
                System.out.println(bolos.bolos);
            }
            ois.close();
        }
        
        private static class Bolos implements Serializable {
    
            private static final long serialVersionUID = -7355538899582009108L;
            int bolos;
            public Bolos(int bolos) {
                this.bolos = bolos;
            }
        }
    }
    
    Aqui funciona na boa, vê lá se detectas o porquê de não funcionar no teu.
     
  20. Baderous

    Baderous Banido

    Não é necessário porque ele está a usar streams aninhadas:
    http://java.sun.com/developer/technicalArticles/Streams/ProgIOStreams/
    Se não fechares a stream depois de cada escrita, funciona. Mas se fechares, é lançada uma StreamCorruptedException pelas razões que já indiquei.

    Quanto ao código do napalm, funciona mas não aparece o warning que eu referi porque ele está a usar o @SuppressWarnings("unchecked"). http://groups.google.com/group/comp.../thread/3c05ddbbe4eaaba4#doc_585daaa682e4e563
     
    Última edição: 8 de Janeiro de 2009

Partilhar esta Página