Serializacja obiektów (problem - wczytywanie [eofexception])

0

Na samym początku chciałbym zaznaczyć, że program w którym używam poniższych metod służących do wczytywania i zapisywania działa prawidłowo (prawie). Jednak przy użyciu metody "wczytajFilmy()" wyskakują komunikaty o błędach.

Komunikat, który wyskakuje w kompilatorze:
Kino.java:413 - linia w której wywołuje metodę "wczytajFilm()"
Kino.java:426 - linia w której wywołuje metodę "wczytajFilm()"
Kino.java:374 - linia w metodzie "wczytaj Film()" (patrz w kodzie metod)

java.io.EOFException
at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2601)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1319)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at kino.ramkaFilm.wczytajFilmy(Kino.java:374)
at kino.ramkaFilm.pokazFilmy(Kino.java:413)
at kino.ramkaFilm$actionPokazWszystkie.actionPerformed(Kino.java:426)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2346)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
at java.awt.Component.processMouseEvent(Component.java:6527)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3321)
at java.awt.Component.processEvent(Component.java:6292)
at java.awt.Container.processEvent(Container.java:2234)
at java.awt.Component.dispatchEventImpl(Component.java:4883)
at java.awt.Container.dispatchEventImpl(Container.java:2292)
at java.awt.Component.dispatchEvent(Component.java:4705)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4898)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4533)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4462)
at java.awt.Container.dispatchEventImpl(Container.java:2278)
at java.awt.Window.dispatchEventImpl(Window.java:2739)
at java.awt.Component.dispatchEvent(Component.java:4705)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:746)
at java.awt.EventQueue.access$400(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:697)
at java.awt.EventQueue$3.run(EventQueue.java:691)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.awt.EventQueue$4.run(EventQueue.java:719)
at java.awt.EventQueue$4.run(EventQueue.java:717)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:716)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

Kod metod:

ArrayList<Film> listaFilmow = new ArrayList<>();
    
    void zapiszFilmy() {
        try {
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Filmy.ser"));
            int size = listaFilmow.size();
            for(int i=0; i<size; i++) {
                Film film = (Film) listaFilmow.get(i);
                oos.writeObject(film);
            }
            oos.close();
        }
        catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    
    void wczytajFilmy() {
        ObjectInputStream ois;
        Film film;
        try {
            int size = listaFilmow.size();
            while(size != 0) {
                listaFilmow.remove(size);
                size--;
            }
            
            ois = new ObjectInputStream(new FileInputStream("Filmy.ser"));
            
            int r = ois.available();
            
            while(ois != null) {
                film = (Film) ois.readObject(); [linia 374]
                listaFilmow.add(film);
            }
            ois.close();
        }
        
        catch(Exception ex) {
            ex.printStackTrace();
        }
    }

Dodam, że niedawno zacząłem przygodę z Javą więc mogłem popełnić sporo błędów przy tworzeniu powyższych metod. Zadaniem tych funkcji jest zapisanie zawartości ArrayList o nazwie listaFilmow przechowujących obiekty typu Film do pliku Filmy.ser oraz przy ponownym uruchomieniu aplikacji zapisanie obiektów odczytanych z tego pliku ponownie do listyFilmow. Jeżeli jest to źle zrobione mógłbym prosić o ponowne napisanie tych metod. Co prawda wszystko odbywa się w moim programie poprawnie, wszystkie obiekty wczytywane z Filmy.ser prawidłowo umieszczane są w ArrayList (mogę z tych obiektów korzystać bez problemu). Działanie programu nie jest przerywane. Uciążliwe są te komunikaty. Po pierwszej linijce java.io.EOFException myślę, że może mieć to coś wspólnego z wyjątkami. Jak to wyeliminować?

1

while(ois != null) <--wczytujesz póki referencja jest różna od null. Coś chyba nie tak nie sądzisz? :)
Z tego co patrze po API - nie zapewnia ono jakiejś ładnej metody na sprawdzenie czy jeszcze mamy coś do odczytania. W takim razie możemy czekać na rzucenie wyjątku EOF, ale nie jest to dobry sposób. Tutaj proponowane podejście do problemu: http://stackoverflow.com/questions/2626163/java-fileinputstream-objectinputstream-reaches-end-of-file-eof

Poza tym do wyczyszczenia ArrayList możesz użyć metody clear http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html

Kolejna rzecz, zamknięcia zasobów powinny odbywać się w bloku finally tak aby była pewność, że sie wykonają. U Ciebie nie ma tej pewności.

0

Tyle godzin męczyłem się nad wyeliminowaniem tego błędu, a ty podsyłasz mi linka z rozwiązaniem. Wielkie dzięki ;)!

Poprawiona wersja:

void wczytajFilmy() {
        ObjectInputStream ois;
        Film film;
        FileInputStream fis;
        try {        
            listaFilmow.clear();
            
            fis = new FileInputStream("Filmy.ser");
            ois = new ObjectInputStream(fis);
            
            while(fis.available() > 0) {
                film = (Film) ois.readObject();
                listaFilmow.add(film);
            }
            ois.close();
        }
        
        catch(Exception ex) {
            ex.printStackTrace();
        }
    } 
1

Jeśli chodzi o available:

This only works if ObjectInputStream doesn't do any buffering. Is this the case? The javadoc doesn't tell anything about this. – Daniel Alder Mar 26 at 11:19

Można zastosować metodę z zatwierdzonego postu zapisując na początku pliku ilość rekordów :)

1

Nie rozumiem dlaczego komplikujecie sobie życie pisząc i czytając w pętli. Przecież można zapisać i odczytać całą kolekcję jednym poleceniem.
Kod czyszczący listę

int size = listaFilmow.size();
while(size != 0) {
      listaFilmow.remove(size);
      size--;
}

jest całkowicie błędny. Niepustej listy nie wyczyści, natomiast rzuci IndexOutOfBoundsException.

0

ja nie rozumiem po co w ogóle czyścić liste? nie lepiej stworzyć nowy obiekt array list i poczekać aż starym się zajmie GC ?

1 użytkowników online, w tym zalogowanych: 0, gości: 1