Zapis do pliku - zapętlenie, tworzony ogromny plik.

0

Witam, to mój pierwszy post, więc proszę o wyrozumiałość w razie jakichś nieścisłości, aczkolwiek chciałbym ich uniknąć. :-)
Na razie jestem na początku swojej drogi "zabawy" z Javą, więc proszę o w miarę nieskomplikowane sugestie, ale do konkretu.
Mam następujący problem - chcę zapisać tablicę piętnastoelementową do pliku dane.txt, po czym je odczytać grupowo - najpierw stożki, potem koła, punkty czy walce (posiadam klasy Punkt, Kolo, Stozek i Walec - czesc z nich od siebie wzajemnie dziedziczy).
Odczytem się jeszcze za bardzo nie zajmowałem, gdyż mam problemy z zapisem do pliku - mianowicie po uruchomieniu programu zapętla się on i powstaje gigantyczny plik dane.txt (kilkaset MB, a pewnie i tyle, ile by miejsca starczyło, gdybym nie przerwał tego procesu), w którym znajduje się wciąż jeden wpis (zawartość a[0]), a nie nawet cała tablica.
Moje pytanie - co mam zrobić, by program normalnie zapisał tablicę do pliku (i potem ją ewentualnie odczytał)?
Jeżeli są jakieś inne błędy w kodzie, to również byłbym wdzięczny za ich wskazanie.

import java.io.*;
import java.util.*;
public class Main implements Iterable
{
 static ArrayList tab = new ArrayList(); 
 int size = tab.size();
 
 public Iterator iterator()
 {
     return new Iterator()
     {
         int position = 0;
         public boolean hasNext()
         {
             return position < size;
         }
         public Object next()
         {
             return tab.get(position++).toString();
         }
         public void remove()
         {
            throw new UnsupportedOperationException();
         }
     };
 }

 public static void main(String args[])
 throws IOException //Czy to potrzebne?
 {   
    
    int wybor; 
    BufferedReader brIn = new BufferedReader(new InputStreamReader(System.in));
    System.out.println("Wypełnij tablicę danymi figurami.");
    
    Punkt punkt = new Punkt(Math.random(), Math.random());
    Kolo kolo = new Kolo(Math.random());
    Walec walec = new Walec(Math.random(), Math.random());
    Stozek stozek = new Stozek(Math.random(), Math.random(), Math.random());
    
    RandomAccessFile wyjscie = null;
     try
     {
          wyjscie = new RandomAccessFile("dane.txt", "rw");
     }
     catch(FileNotFoundException e)
     {
          System.out.println("Nie znaleziono pliku.");
     }     
     
    for (int i = 0; i < 15; i++)
    {
        System.out.println("Wybierz: 1 - punkt, 2 - koło, 3 - stożek, 4 - walec.");
        
        String line = null;
               try{ 
                   line = brIn.readLine();
                }
               catch(IOException e){
                   System.out.println("Błąd odczytu strumienia.");
                   return;
                }
                
               try{
                   wybor = Integer.parseInt(line);
                }
               catch(NumberFormatException e){
                   System.out.println("Wprowadzona wartość nie jest liczbą całkowitą.");
                   return;
                }        
        switch(wybor)
        {
              case 1: {
                        tab.add(punkt);
                      }
              break;
              case 2: {
                        tab.add(kolo);
                      }
              break;
              case 3: {
                        tab.add(walec);
                      }
              break;
              case 4: {
                        tab.add(stozek);
                      }
              break;
              default: System.out.println("Nie ma figury o takim numerze."); break;     
        }
    }
     
   
    RandomAccessFile wejscie = null;
     try
     {
          wejscie = new RandomAccessFile("dane.txt", "r");
     }
     catch(FileNotFoundException e)
     {
          System.out.println("Nie znaleziono pliku.");
     }
    
     //Właściwa treść zapisu.
     String line = null;
     
    int indeks = 0;
    System.out.println("\nWyświetlenie tablicy.\n");
    for(Object o: tab)
    {
        System.out.println("a[" + indeks + "] = " + o.toString());
        indeks++;
        try
     {
         while(o.toString() != null)
         {
             wyjscie.writeBytes(o.toString() + "\n");
         }
     wyjscie.close();
     }
     catch(IOException e)
     {
         System.out.println("Błąd wejścia/wyjścia.");
         return;
     }
    }
 }
}
0

kiedy nastąpi wyjście z tej pętli ?

         while(o.toString() != null)
         {
             wyjscie.writeBytes(o.toString() + "\n");
         }
0
bogdans napisał(a)

kiedy nastąpi wyjście z tej pętli ?

         while(o.toString() != null)
         {
             wyjscie.writeBytes(o.toString() + "\n");
         }

Wiem, że tutaj jest błąd (bo wyjście z pętli nie nastąpi), ale sądziłem, że skoro wcześniej pętlą for generuję tablicę piętnastu elementów, to tyle ich powinno się zapisać. Zdaję sobie sprawę, że jestem w błędzie, ale nie wiem, jak jedno (zapis pliku) "uzależnić" od tych piętnastu elementów, a nie, żeby pętla nie miała końca.

0

A czemu nie tak ?

    for(Object o: tab)
    {
        System.out.println("a[" + indeks + "] = " + o.toString());
        indeks++;
        try
        {

             wyjscie.writeBytes(o.toString() + "\n");
        }
        catch(IOException e)
        {
            System.out.println("Błąd wejścia/wyjścia.");
            return;
        }
    }
    wyjscie.close();

Jeśli chcesz zapisywać obiekty do plików, to skorzystaj raczej z serializacji.
Wygląda, to mniej więcej tak:

  1. public class Kolo extends ... implements Serializable
  2. zapisywanie
            try
            {
                FileOutputStream f=new FileOutputStream(nameOfFile);
                ObjectOutputStream str=new ObjectOutputStream(f);
                str.writeObject(ob);
                // ob jest zapisywanym obiektem
                str.flush();
                f.close();
            }
            catch(IOException e)
            {
                JOptionPane.showMessageDialog(lista,e.getMessage(),"Pisanie do pliku "+nameOfFile,JOptionPane.INFORMATION_MESSAGE);
            }
  1. odczytywanie
            try
            {
                FileInputStream f=new FileInputStream(nameOfFile);
                ObjectInputStream ois=new ObjectInputStream(f);
                ob=ois.readObject();
            }
            catch(Exception e)
            {
                JOptionPane.showMessageDialog(null,e.getMessage(),"Czytanie pliku "+nameOfFile,JOptionPane.INFORMATION_MESSAGE);
                lista=new List();
            }
0
         while(o.toString() != null)
         {
             wyjscie.writeBytes(o.toString() + "\n");
         }

</quote>

Ten while jest w ogóle bez sensu... Dla każdego obieku z tablicy wypisujesz go nieskończoną liczbę razy bo toString() nigdy nie zwróci tutaj null.

Po co w ogóle ten while, co on ma na celu? Odpowiedz sobie na to pytanie bo pewnie okaże się, że jest on w ogóle niepotrzebny, a uzależnienie od liczby elementów tablicy uzyskasz poprzez pętlę

for
0

Dzięki, bogdans, za pomoc. Faktycznie usunąłem tego while'a i teraz się zapisuje poprawnie do pliku. :-)
Gzrewal, tak, teraz wiem, że to bez sensu - sądziłem po prostu, że skoro tworzona jest tablica piętnastu elementów, to pętla while przeczyta tylko tyle elementów i stąd taki, a nie inny warunek. Jak widać, byłem w błędzie.
Bogdans, co do Twoich dwóch pozostałych kodów... A da się zapisać plik w ten sposób, który to zrobiłem (czyli bez serializacji) i odczytywać z niego dane obiektami po kolei? Czy muszę używać serializacji, jeśli chcę to zrobić?

0

Pewnie się da. Metoda toString() musi zapisać tyle informacji o obiekcie, żeby się dało go odtworzyć. Dodatkowo, trzeba napisać konstruktor, który na podstawie odczytanego stringu stworzy obiekt.

0
bogdans napisał(a)

Pewnie się da. Metoda toString() musi zapisać tyle informacji o obiekcie, żeby się dało go odtworzyć. Dodatkowo, trzeba napisać konstruktor, który na podstawie odczytanego stringu stworzy obiekt.

Dzięki za informację, poszukam trochę po książkach i w Internecie, co i jak, a jeśli się nie uda odczytywać tych obiektów grupami (punkty, stożki, walce, koła), to spróbuję skorzystać z Twojego sposobu z serializacją. [green]

0

Przepraszam za pisanie posta pod postem, jednak gdybym edytował ten poprzedni (co zrobiłem przed chwilą), to mój temat nie "powędrowałby" na listę świeżych tematów i najpewniej nikt by tu nie zajrzał...
Do sedna.

Jednak nie udało mi się znaleźć niczego odpowiedniejszego niż serializacja, jeśli chodzi o czytanie obiektów. ;-P
Dodałem więc do każdej klasy "implements Serializable" oraz do klasy Main (tej, którą tutaj wciąż wklejam) dodałem poniższy (lekko przerobiony - nazwy zmiennych i komentarze właściwie), który bogdans wpisał na forum, czyli:

 //Zapisywanie do pliku.
    try
            {
                FileOutputStream f = new FileOutputStream("dane.txt");
                ObjectOutputStream str = new ObjectOutputStream(f);
                str.writeObject(punkt);
                //punkt jest zapisywanym obiektem //było "ob"
                str.flush();
                f.close();
            }
            catch(IOException e)
            {
                System.out.println("Błąd wejścia/wyjścia.");
             //   JOptionPane.showMessageDialog(lista,e.getMessage(),"Pisanie do pliku "+nameOfFile,JOptionPane.INFORMATION_MESSAGE);
            } 
    
    //Odczyt danych z pliku.
    try
            {
                FileInputStream f = new FileInputStream("dane.txt");
                ObjectInputStream ois = new ObjectInputStream(f);
                punkt = ois.readObject();
            }
            catch(Exception e)
            {
               System.out.println("Błąd wejścia/wyjścia.");
              // JOptionPane.showMessageDialog(null,e.getMessage(),"Czytanie pliku "+nameOfFile,JOptionPane.INFORMATION_MESSAGE);
              // lista=new List();
            }

Problem jest następujący - bo choć plik jest (chyba) zapisywany poprawnie, to już odczyt danych nie chce się kompilować, pokazując wciąż niezgodność typów w linii (incompatible types - found java.lang.Object but expected Punkt):

punkt = ois.Object();

Nie wiem, czy to ma znaczenie, ale dane są przechowywane w tablicy obiektów:

Object a[];

Jak to naprawić?
Z góry dziękuję za (p)odpowiedź. :-)

0

Słowo kluczowe: RZUTOWANIE

Skoro wiesz jaki obiekt czytasz ze strumienia to go przerzutuj na Punkt...

HTH

0
gzrewal napisał(a)

Słowo kluczowe: RZUTOWANIE

Skoro wiesz jaki obiekt czytasz ze strumienia to go przerzutuj na Punkt...

HTH

Jako że z rzutowania jeszcze nie korzystałem, to dziś zacząłem się gruntownie edukować w tej mierze, jednak - wstyd się przyznać - nie wiem, jak to zrobić w tym przypadku. [wstyd]
Bo skoro wszystkie dane są przechowywane w tablicy obiektów:

Object a[];

natomiast deklaracja obiektów wygląda w następujący sposób:

Punkt punkt = new Punkt(Math.random(), Math.random());
Kolo kolo = new Kolo(Math.random());
Walec walec = new Walec(Math.random(), Math.random());
Stozek stozek = new Stozek(Math.random(), Math.random(), Math.random());

To w końcu np. obiekt punkt jest klasy Punkt czy Object?
Teoretycznie wydawało mi się, że jest klasy Punkt (wszakże Object jest praklasą), ale błąd przy kompilacji o treści "incompatible types - found java.lang.Object but expected Punkt" podkopuje we mnie tę pewność.
Jak więc przeprowadzić to rzutowanie, by program działał i odczytywał z pliku kolejne grupy obiektów, jakie mu wskażę?
Z góry dziękuję za pomoc. ;-)

0

Gdyby w pliku "Dane.txt" były same obiekty typu Punkt, to powinno być tak:

  punkt = (Punkt)ois.readObject();

Jeśli jest "mieszanka", a chcesz w jednym przebiegu odczytać do jednej tablicy Object[] all, to powinieneś to robić tak:

    Object ob=ois.readObject()
    if (ob instanceof Punkt)
    {
       all[i++]=(Punkt)(ob);
    }
    if (ob instanceof Walec)
    {
       all[i++]=(Walec)(ob);
    }
    ....
0

Poniżej Twój własny kod; zauważ że w nim sam a priori zakładasz, że czytasz ze strumienia obiekt typu punkt (patrz komentarz)

//Odczyt danych z pliku.
    try
            {
                FileInputStream f = new FileInputStream("dane.txt");
                ObjectInputStream ois = new ObjectInputStream(f);
                punkt = ois.readObject(); //!!! Skoro przypisujesz do Punkt punkt to wydajesz się być pewien, 
                                                      //że odczytasz punkt. Kompilator w takiej sytuacji też chciałby mieć
                                                      //Twoją pewność..., inna sprawa, czy jesteś pewien, że ze strumienia 
                                                      //przyjdzie punkt i tutaj patrz @bogdans
            }

Pozdrawiam,

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