Baderous Posted June 9, 2008 at 02:41 PM Report #190252 Posted June 9, 2008 at 02:41 PM Tenho dúvidas relativamente à codificação de métodos de leitura/escrita em ficheiros usando streams. Tenho em ideia que os métodos de escrita, quer usando streams de objectos, quer de caracteres, devem ser codificados nas classes que pretendemos que implementem a possibilidade de serem escritas em ficheiro. Mas será que estou certo? É que já vi nos apontamentos da cadeira de Java que estou a fazer que existia um método de escrita de caracteres em ficheiro definido na classe e depois existia outro igual definido na classe de teste. Podem ver aqui. Estou a falar da classe Stock com o método gravaTxt e da classe TesteStock com o método gravaFichTxt. Também não sei onde devem ser escritos os métodos de leitura. É na classe de teste (quer leitura usando streams de objectos, quer de caracteres)? Depois, também relacionado com o problema anterior, tenho dúvidas relativas ao modo como estes métodos devem ser codificados. Porque às vezes, vejo os métodos escritos com try-catch, mas noutras vejo escrito com throws excepção no cabeçalho, sendo o try-catch feito quando a classe principal invoca esse método. Sei que se se colocar no cabeçalho do método as excepções que são lançadas, pode-se depois fazer o try-catch na invocação do método, mas, segundo aquilo que li, esse método deve ter algures no seu código, uma instrução throw excepção (a qual será tratada então no try-catch). O que acontece (como podem ver no pdf que postei) é que não é escrito qualquer throw nos métodos e isso está-me a fazer alguma confusão. Alguém que me explique, porque isto parece-me ser apenas uma questão de escrever as coisas correctamente.
Baderous Posted June 9, 2008 at 06:34 PM Author Report #190326 Posted June 9, 2008 at 06:34 PM Depois, também relacionado com o problema anterior, tenho dúvidas relativas ao modo como estes métodos devem ser codificados. Porque às vezes, vejo os métodos escritos com try-catch, mas noutras vejo escrito com throws excepção no cabeçalho, sendo o try-catch feito quando a classe principal invoca esse método. Sei que se se colocar no cabeçalho do método as excepções que são lançadas, pode-se depois fazer o try-catch na invocação do método, mas, segundo aquilo que li, esse método deve ter algures no seu código, uma instrução throw excepção (a qual será tratada então no try-catch). O que acontece (como podem ver no pdf que postei) é que não é escrito qualquer throw nos métodos e isso está-me a fazer alguma confusão. Relativamente a esta parte, acho que já percebi, pelo menos a questão de uns não terem throw no meio do código e outros terem. Penso que só têm throw aqueles métodos onde as excepções que são explícitas (programadas), os outros (implícitas, ou seja, lançadas automaticamente pela JVM) não têm (por ex: IOException). Mesmo assim gostava de saber a vossa opinião.
Knitter Posted June 9, 2008 at 11:45 PM Report #190414 Posted June 9, 2008 at 11:45 PM A forma como irás colocar os métodos de escrita é, como em qualquer outra questão relacionada com POO, dependente do sistema que estás a modelar e como pretendes que esse sistema funcione. Em termos de funcionalidade, é igual colocares os métodos em qualquer objecto dos que mencionaste. Apesar de ter passado apenas os olhos por cima do exemplo, acho que, mesmo existindo os dois métodos, só é usado um, penso que tenha sido criado assim apenas porque é para exemplo. Quando fazes a análise do sistema a implementar, essas questões são resolvidas facilmente no decorrer da análise. Se tivesse de arriscar uma "regra", dir-te-ia que o objecto que quer ser gravado deve implementar os métodos de gravação. Mas se pensarmos, por exemplo, num programa que guarda endereços de pessoas, em que temos a classe Pessoa e classe LivroDeEnderecos, o que fará mais sentido, ser a classe pessoa ou a classe LivroDeEnderecos a ter os métodos de gravação? Neste caso acho que deverá ser a classe LivroDeEndereços, dado que nós gravamos livros, abrimos livros, etc. Mas será que essa classe deverá saber guardar pessoas? Ou a classe Pessoa deve saber guardar os seus atributos? Se pensarmos em caso de encapsulamento, terá de ser a classe Pessoa a guardar os seus atributos dado que podem existir condições especiais que só essa classe sabe resolver. Assim terias a classe LivroDeEndereco que sabe guardar os seus atributos, neste caso, percorrer todas as pessoas que contém e dizer-lhes para se guardarem, dado que apenas elas sabem guardar o seu estado interno. Resumindo, depende do que tens de fazer 😞 Quanto a apanhar as excepções ou propagar, novamente depende do que estás a fazer, pessoalmente acho melhor que as excepções de IO sejam apanhadas logo no sítio onde são criadas, isto porque as excepções servem para controlo de erros. No caso das streams, deves fecha-las no método onde as abriste. Repara que se no método grava abres uma stream e em vez de apanhares uma possível excepção e a propagares, colocando na assinatura do método a excepção que o método lança, não vais conseguir fechar a stream, uma vez que esse método vai terminar e o controlo de execução irá para o método que o invocou, a não ser que este último método tenha acesso à stream que foi aberta, perdeste a referencia e não vais conseguir fechar uma stream onde ocorreu um erro. Resultado, vais ficar com recursos pendentes na aplicação, vais consumir mais recursos que devias. 1 Report
Baderous Posted June 10, 2008 at 01:50 PM Author Report #190479 Posted June 10, 2008 at 01:50 PM Ok, acho que já percebi. Isto agora vai lá com um bocado de treino. Thanks!
Baderous Posted June 23, 2008 at 03:07 PM Author Report #193049 Posted June 23, 2008 at 03:07 PM Estou outra vez com dúvidas nesta cena. Quero que uma classe que eu criei com 5 variáveis de instância seja gravada numa ObjectStream. Agora não sei é como codificar o método. Hipótese 1: Indico que o método lança 1 excepção, a qual trato apenas na main, quando o invoco. public void gravaObjStream(String fich) throws IOException { ObjectOutputStream oout = new ObjectOutputStream(new FileOutputStream(fich)); oout.writeObject(this); oout.flush(); oout.close(); } /* Na main faço o tratamento */ ... try { gravaObjStream(ficheiro); } catch(IOException e) {System.out.println(e.getMessage()); } Hipótese 2: Faço o tratamento da excepção no método que a lança. public void gravaStreamObj(String fich) throws IOException { ObjectOutputStream oout = new ObjectOutputStream(new FileOutputStream(fich)); try { oout.writeObject(this); } catch(IOException) { System.out.println(e.getMessage()); } finally { oout.flush(); oout.close(); } } Acho que, segundo o post do Knitter, a 2ª opção é a melhor pois o tratamento é local e permite o fecho da stream em caso de existir uma excepção, certo? Btw, o código da 2ª hipótese está correcto, isto é, deve ter no cabeçalho o throws IOException, sendo o tratamento feito localmente? E quanto ao finally, está bem colocado ali com as 2 instruções de flush e close?
Knitter Posted June 23, 2008 at 03:21 PM Report #193056 Posted June 23, 2008 at 03:21 PM Btw, o código da 2ª hipótese está correcto, isto é, deve ter no cabeçalho o throws IOException, sendo o tratamento feito localmente? E quanto ao finally, está bem colocado ali com as 2 instruções de flush e close? Se apanhas a excepção então na vale a pena colocares a indicação que a vais lançar, aliás, esse código não deve compilar 😛 Depois, o flush deve ser feito na situação normal, pelo que terá de passar para o bloco try. Mas repara que podes estar a fazer um flush desnecessário, o close já faz um flush. Quanto ao finally, não estás a ter em consideração que quando ocorre uma excepção, a variável oout pode não estar iniciada, pelo que ao fazeres oout.close() podes ter uma NullPointerException, que por não estares a apanhar, vai ser propagada até ao utilizador 😄 Uma nota, não se apanham runtime exceptions por isso, apesar de ter dito que não estavas a apanhar a NPE, não quero dizer que a terás de apanhar, apenas que terás de prevenir a situação. Exemplo: public void gravaStreamObj(String fich) { ObjectOutputStream oout = null; try { oout = new ObjectOutputStream(new FileOutputStream(fich)); oout.writeObject(this); } catch(IOException e) { e.printStackTrace();//Correctamente deverias efectuar o logging da excepção. //System.out não é garantido que seja apresentado. //Neste exemplo também não estou a fazer logging }finally { if(oout != null) {//oout pode estar a null oout.close(); } } } Caso pretendas usar o mecanismo de excepção para controlo fora deste método, coisa que deves fazer sempre que seja algo que o utilizador possa fazer, podes propagar a excepção. public void gravaStreamObj(String fich) throws MinhaExcepcao { ObjectOutputStream oout = null; try { oout = new ObjectOutputStream(new FileOutputStream(fich)); oout.writeObject(this); } catch(IOException e) { MinhaExcepcao me = new MinhaExcepcao ("Falhou: " + e); me.initCause(e); throw me; } finally { if(oout != null) {//oout pode estar a null oout.close(); } } }
Baderous Posted June 23, 2008 at 04:04 PM Author Report #193069 Posted June 23, 2008 at 04:04 PM Percebi a 1ª solução, mas quanto à 2ª não percebi: Caso pretendas usar o mecanismo de excepção para controlo fora deste método, coisa que deves fazer sempre que seja algo que o utilizador possa fazer, podes propagar a excepção. Não percebi muito bem esta frase. No exemplo que dás depois, lanças uma excepção MinhaExcepcao. É essa que será tratada então pelo utilizador (que é o que me parece com o throw me)? Se sim então no método que invoca gravaStreamObj, deverei ter algo: try { gravaStreamObj(file); } catch(MinhaExcepcao e) { e.printStackTrace(); } ?
Knitter Posted June 23, 2008 at 05:02 PM Report #193083 Posted June 23, 2008 at 05:02 PM +/-, o método printStackTrace(), termina a execução da aplicação mostrando o registo da stack onde aconteceu a excepção. Por isso deves apanhar a excepção mas deverás tratá-la convenientemente 😛 Não tens necessariamente de criar uma excepção nova, podes simplesmente propagar a excepção que recebeste dentro do catch.
Baderous Posted June 23, 2008 at 05:22 PM Author Report #193089 Posted June 23, 2008 at 05:22 PM Para soluções futuras, e enquanto não dominar isto, vou usar a 1ª opção que me deste, que vai mais de encontro a estes 2 exemplos: http://www.javadb.com/writing-objects-to-file-with-objectoutputstream http://www.javadb.com/reading-objects-from-file-using-objectinputstream
Baderous Posted June 24, 2008 at 05:31 PM Author Report #193258 Posted June 24, 2008 at 05:31 PM Imaginemos que tinha uma classe Tipo que implementava um determinado tipo de qualquer coisa. Depois tinha uma classe Lista que implementava uma Lista de Tipos. Depois tinha uma classe teste, onde criava uma instância dessa Lista com vários Tipos lá dentro e guardava num ficheiro de objectos. Se depois eu quiser ler desse ficheiro de objectos essa mesma lista e reconstituí-la, tenho de, obrigatoriamente implementar, quer na classe Lista, quer na Tipo, métodos de leitura de ObjectStream, para que os objectos possam ser reconstituídos correctamente, certo?
Knitter Posted June 24, 2008 at 05:53 PM Report #193266 Posted June 24, 2008 at 05:53 PM Se estás a falar de ObjectStream, estás a falar de Serialização certo? Então depende, se estiveres a serializar a classe Lista, então todos os seus objectos têm de ser serializáveis. Se estás a serializar os objectos dentro da lista então a lista não precisa ser serializável. Se estiveres a usar as listas do Java, não vejo porque não estejas, então as listas já são serializáveis. Não sei se respondi à pergunta.
Baderous Posted June 24, 2008 at 06:16 PM Author Report #193273 Posted June 24, 2008 at 06:16 PM Quanto à serialização, todas as minhas classes implementam a interface Serializable. Pegando num exemplo prático: Seja EmpresaList uma classe que implementa um ArrayList de Empregados, tendo EmpresaList e Empregados implementado a interface Serializable. Se numa classe de teste onde queiramos ler uma EmpresaList de um ficheiro de objectos fizermos o seguinte: EmpresaList lstEmp = new EmpresaList(); try { ObjectInputStream ooin = new ObjectInputStream(new FileInputStream("emp1.obj")); lstEmp = (EmpresaList) ooin.readObject(); ooin.close(); } catch (IOException e) {...} catch (ClassNotFoundException ec) {...} Conseguimos reconstruir correctamente a instância de EmpresaList?
Knitter Posted June 24, 2008 at 06:29 PM Report #193274 Posted June 24, 2008 at 06:29 PM Esta linha, EmpresaList lstEmp = new EmpresaList();, é desnecessária, pelo menos a iniciação dado que depois vais substituir a instância. E sim, consegues reconstruir correctamente a lista, tens de ter atenção que se gravares um objecto, depois alterares alguma coisa na classe e tentares ler o objecto, os dados guardados são inválidos pelo que perdes os dados. Mas sim, se guardaste apenas uma lista então ao leres vais recuperar essa lista e todos os elementos que não sejam transient.
Baderous Posted June 24, 2008 at 06:46 PM Author Report #193278 Posted June 24, 2008 at 06:46 PM Ok, era isso que precisava de saber.
Guest id194 Posted June 24, 2008 at 07:17 PM Report #193280 Posted June 24, 2008 at 07:17 PM Não li este tópico todo pois já está demasiado grande e peço desculpa se repetir o que já foi dito. Mas, se reparares, na última página do PDF "STREAMS_JAVA_ESSENCIAL" que está no site da cadeira fala como deves codificar os métodos de escrita/leitura. Pessoalmente, estou a fazer da seguinte forma. Cada classe tem um método estático para ler o objecto e um método "normal" que escreve o objecto e o código é igual ao seguinte com as diferenças necessárias para cada classe: public static FichaTripulante carregaObjecto(String ficheiro) throws IOException, ClassNotFoundException { ObjectInputStream objInputStream = new ObjectInputStream(new FileInputStream(ficheiro)); FichaTripulante fichaTripulante = (FichaTripulante)objInputStream.readObject(); objInputStream.close(); return fichaTripulante; } public void gravaObjecto(String ficheiro) throws IOException { ObjectOutputStream objOutputStream = new ObjectOutputStream(new FileOutputStream(ficheiro)); objOutputStream.writeObject(this); objOutputStream.close(); } Depois é só usa-los... E como ambos lançam excepções, somos obrigados a ter try/catch onde chamar-mos estes métodos. Só uma dúvida relativamente ao flush, ele é mesmo chamado quando se faz um close? É que em todos os documentos/exemplos do prof, ele chama sempre o flush antes do close... E acho estranho ele fazer isso se realmente não fosse necessário.
Baderous Posted June 24, 2008 at 08:13 PM Author Report #193288 Posted June 24, 2008 at 08:13 PM E porque é que tens um método de leitura em cada classe? Nos restantes exemplos de exercícios, as classes tinham apenas os métodos de escrita, sendo o método de leitura codificado na classe de teste. Será essencial ter um método de leitura em cada classe?
Guest id194 Posted June 24, 2008 at 08:17 PM Report #193289 Posted June 24, 2008 at 08:17 PM No meu caso, retorno sempre o tipo da classe que estou a ler em vez de ter um global que devolva um objecto... Se fosse um object, como é que eu depois saberia o tipo dele? Eu sei que há maneiras de o fazer, mas assim é mais directo...
Knitter Posted June 24, 2008 at 08:48 PM Report #193299 Posted June 24, 2008 at 08:48 PM Só não concoerdo com uma coisa nesse código, ao ocorrer uma excepção não é possível fechar a stream, deixas recursos pendurados na aplicação. Quanto ao close, o comportamento normal é ele fazer um flush, pode acontecer que não esteja a ser feito, mas um close deverá libertar todos os recursos associados, o que implicará esvaziar qualquer buffer que seja usado. Se repararem que os vossos dados não estão a ser guardados pode ser por isso, experimentem invocar um flush. Estive a ver a documentação e no caso da ObjectOutputStream não é indicado se faz ou não um flush.
Guest id194 Posted June 24, 2008 at 09:28 PM Report #193323 Posted June 24, 2008 at 09:28 PM Eu estava realmente a falar apenas do ObjectOutputStream. Em todas as minhas classes tinha um flush() antes do close() mas removi essa linha por alguma razão (só não me lembro qual), mas agora que tive a ver todos os exemplos de código do prof, ele tem um flush e por isso estou na dúvida...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now