Deserializacja obiektów w pętli

0

Mam problem z wymyśleniem warunku dla pętli służącej do deserializacji obiektów. Dajmy przykład, że nie wiem ile obiektów jest w pliku i muszę wymyślić jakiś warunek, który będzie czytał dane dopóki się nie skończą. Ten co mam teraz w kodzie jest oczywiście zły.

import java.io.File;
import java.io.FileInputStream;
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.Collections;
import java.util.List;
import java.util.Scanner;
 
class Test {
     
    static public void main(String[] args) throws IOException, ClassNotFoundException {
         
        @SuppressWarnings("serial")
        class Person implements Comparable<Person>, Serializable {
            String name, lastName;
            int age;
             
            void setName(String name) {
                this.name = name;
            }
            void setLastName(String lastName) {
                this.lastName = lastName;
            }
            void setAge(int age) {
                this.age = age;
            }
             
            final String getName() {
                return name;
            }
            final String getLastName() {
                return lastName;
            }
            final int getAge() {
                return age;
            }
             
            @Override
            public int compareTo(Person person) {
                int porownanieImion = name.compareTo(person.name);
                 
                if(porownanieImion == 0) {
                    return lastName.compareTo(person.lastName);
                }
                else {
                    return porownanieImion;
                }
            }
        }
         
        String name, lastName;
        int age;
         
        int ile;
         
        @SuppressWarnings("resource")
        Scanner input = new Scanner(System.in);
         
        System.out.print("Ile obiektow chcesz stworzyć: ");
         
        ile = input.nextInt();
         
        List<Person> list = new ArrayList<Person>();
         
        for(int i = 0; i < ile; ++i) {   
             
            Person person = new Person();
            list.add(person);
             
            System.out.print("Obiekt " + (i+1) + " Name : ");
            name = input.next();
            list.get(i).setName(name);
            System.out.print("Obiekt " + (i+1) + " Last name : ");
            lastName = input.next();
            list.get(i).setLastName(lastName);
            System.out.print("Obiekt " + (i+1) + " Age : ");
            age = input.nextInt();
            list.get(i).setAge(age);
        }
         
        for(Person objectPerson : list) {
            System.out.println("Obiekt " + list.indexOf(objectPerson) + " Name: " + objectPerson.getName());
            System.out.println("Obiekt " + list.indexOf(objectPerson) + " Last name: " + objectPerson.getLastName());
            System.out.println("Obiekt " + list.indexOf(objectPerson) + " Age: " + objectPerson.getAge());
        }
         
        System.out.println("POSORTOWANE");
         
        Collections.sort(list);
         
        for(Person objectPerson : list) {
            System.out.println("Obiekt " + list.indexOf(objectPerson) + " Name: " + objectPerson.getName());
            System.out.println("Obiekt " + list.indexOf(objectPerson) + " Last name: " + objectPerson.getLastName());
            System.out.println("Obiekt " + list.indexOf(objectPerson) + " Age: " + objectPerson.getAge());
        }
         
        File file = new File("file.ser");
         
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
         
        for(Person object2 : list)
        {
            oos.writeObject(object2);
        }
        oos.close();
         
        List<Person> list2 = new ArrayList<Person>();
         
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
         
        while(ois.readObject() != null)
        {
            Person objPerson = new Person();
            list2.add(objPerson);
             
            objPerson = (Person)ois.readObject();
            System.out.println(" Name: " + objPerson.name + " Last name: " + objPerson.lastName + " Age: " + objPerson.age);
        }
        ois.close();
    }
}
1

Użyj metody avaliable(), która zwróci Ci ilość bajtów które są dostępne.
https://docs.oracle.com/javase/7/docs/api/java/io/ObjectInputStream.html#available()

0

Mam wątpliwości co do sensowności użycia metody available. Przy deserializacji trzeba być przygotowanym na obsługę błędów (metoda readObject rzuca pięć rodzajów wyjątków, czytanie po dotarciu do końca pliku dorzuca szósty: EOFException) . Czy kod

                try
                {
                    fis = new FileInputStream(fileName);
                    ObjectInputStream ois = new ObjectInputStream(fis);
                    while(fis.available() > 0)
                    {
                        Person p = (Person)ois.readObject();
                        System.out.println(p);
                    }
                }
                catch(Exception e)
                {
                    System.out.println(e);
                }

jest lepszy od kodu

                try
                {
                    fis = new FileInputStream(fileName);
                    ObjectInputStream ois = new ObjectInputStream(fis);
                    while(true)
                    {
                        Person p = (Person)ois.readObject();
                        System.out.println(p);
                    }
                }
                catch(Exception e)
                {
                    System.out.println(e);
                }
0

Jest lepsze z dwóch powodów.

  1. Próbujesz sterować wyjątkami.
  2. Pracując na ObjectInputStream nie wiążesz się z FileInputStream bo to tylko zwiększa zależność pomiędzy obiektami. Jeżeli będzie chciał serializować/deserializowąć np. z ByteArrayInputStream lub z socketa, to będzie musiał przerabiać kod. Stosując available(), podmieniasz tylko źródło.
0
  1. Przy deserializacji sterowania wyjątkami nie unikniesz.
  2. Metoda available wywołana na ObjectInputStream u mnie zawsze zwraca 0, więc mogę jej użyć tylko do deserializacji z pliku.
0

Sprawdziłem i masz rację z available zwracającym zero. Mimo wszystko uważam że sterowania wyjątkami da się i lepiej uniknąć. FileInputStream można opakować w BufferedInputStream i na nim sprawdzać ilość pozostałych bajtów.

2

Ja tak tylko wspomnę żeby z deserializacją uważać, szczególnie jeśli dane które deserializujesz pochodzą z niezaufanego źródła, bo to jest exploitowalna funkcjonalność:
https://github.com/p4-team/ctf/tree/master/2016-08-21-bioterra-ctf/akashic_records#pl-version
https://github.com/frohoff/ysoserial

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