Przykład ilustruje wykorzystanie: tablicy obiektów, plików tekstowych (BufferedReader
, BufferedWriter
), plików binarnych (RandomAccessFile
), plików obiektów (ObjectInputStrea
, ObjectOutputStrea
), klas StringTokenizer
, StringBuilder
, funkcji String.split
. Można pobrać projekt NetBeans w formacie zip. Uwaga, program nie waliduje zawartości plików i jest podatny na ich niepoprawną zawartość.
// Program prezentuje metody wykonywania operacji na plikach tekstowych, // obiektów i binarnych. Operacje dotyczą informacji o samochodach, odczytywane // dane są zapisywane w tablicy obiektów, operacje zapisu danych pobierają dane // a tej samej tablicy. // UWAGA: nie jest realizowana kontrola poprawności odczytywanych danych, błędy // w pliku będą skutkować błędami w działaniu programu. import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.RandomAccessFile; import java.io.Serializable; import java.util.StringTokenizer; // Obiekty tej klasy będą zapamiętywane w tablicy, będą zapisywane i odczytywane // do/z plkików różnych typów. Implementacja interfejsu Serializable jest // konieczna dla obsługi plików obiektów, nie trzeba jej używać dla plików // tekstowych i binarnych. class Auto implements Serializable { String marka; String model; double pojemnosc; void pokaz() { System.out.println(" Marka: " + marka); System.out.println(" Model: " + model); System.out.println("Pojemność: " + pojemnosc); } } // Klasa prezentująca różne rodzaje plików i spososby realizacji operacji // zapisu i odczytu class EwidencjaAut { // Do tej tablicy będą odczytywane dane, z tej tablicy będą pobierane dane // zapisywane do plików private Auto[] auta = null; void pokaz() { if (auta == null) return; for (int nrAuta = 0; nrAuta < auta.length; ++nrAuta) { System.out.println("Auto nr: " + (nrAuta + 1)); auta[nrAuta].pokaz(); } } // Pliki tekstowe // Odczyt danych do tablicy z pliku tekstowego // Założenie pierwsza linia zawiera liczbę linii zawierających opisy aut // W kolejnych liniach: // marka model pojemność_silnika boolean oczytZPlikuTekstowego(String nazwaPliku) { try (BufferedReader plik = new BufferedReader(new FileReader(nazwaPliku))) { // Odczytanie liczby aut String linia = plik.readLine(); auta = new Auto[Integer.parseInt(linia)]; // Odczyt kolejnych linii opisu auta for (int i = 0; i < auta.length; ++i) { auta[i] = new Auto(); // Utwórz obiekt linia = plik.readLine(); // Czytaj linię // Prezentacja klasy StringTokenizer // Utworzenie tokenizera dla linii, separator to spacja StringTokenizer tok = new StringTokenizer(linia, " "); // Wyodrębnienie trzech elementów z linii auta[i].marka = tok.nextToken(); auta[i].model = tok.nextToken(); auta[i].pojemnosc = Double.parseDouble(tok.nextToken()); } } catch (IOException e) { return false; } return true; } // Zapis danych z tablicy aut do pliku tekstowego // Założenie pierwsza linia zawiera liczbę linii zawierających opisy aut // W kolejnych liniach: // marka model pojemność_silnika boolean zapisDoPlikuTekstowego(String nazwaPliku) { try (BufferedWriter plik = new BufferedWriter(new FileWriter(nazwaPliku))) { // Zapis liczby aut do pliku plik.write(String.valueOf(auta.length)); plik.newLine(); // Zapis kolejnych aut for (int i = 0; i < auta.length; ++i) { // Prezentacja klasy StringBuilder StringBuilder linia = new StringBuilder(); linia.append(auta[i].marka); linia.append(" "); linia.append(auta[i].model); linia.append(" "); linia.append(auta[i].pojemnosc); // Zapis linii "sklejonej" przez obiekt klasy StringBuilder plik.write(linia.toString()); plik.newLine(); } } catch (IOException e) { return false; } return true; } // Pliki obiektów // Zapis danych z tablicy aut do pliku obiektów // Założenie: plik rozpoczyna dana typu int, określająca liczbę aut boolean zapisDoPlikuObiektow(String nazwaPliku) { try (ObjectOutputStream plik = new ObjectOutputStream(new FileOutputStream(nazwaPliku))) { // Zapis liczby aut plik.writeInt(auta.length); // Zapis kolejnych elementów tablicy for (Auto auto : auta) plik.writeObject(auto); } catch (IOException e) { return false; } return true; } // Odczyt danych z pliku obiektów, utworzenie tablicy // Założenie: plik rozpoczyna dana typu int, określająca liczbę aut boolean odczytZPlikuObiektow(String nazwaPliku) { try (ObjectInputStream plik = new ObjectInputStream(new FileInputStream(nazwaPliku))) { // Odczyt liczby aut i utworzenie tablicy auta = new Auto[plik.readInt()]; // Odczyt kolejnych aut, ich liczba jest znana for (int i = 0; i < auta.length; ++i) auta[i] = (Auto) plik.readObject(); } catch (IOException e) { return false; } catch (ClassNotFoundException e) { return false; } return true; } // Pliki binarne (pliki danych) // Zapis danych z tablicy aut do pliku binarnego // Założenie: plik rozpoczyna dana typu int, określająca liczbę aut public boolean zapisDoPlikuBinarnego(String nazwaPliku) { try (RandomAccessFile plik = new RandomAccessFile(nazwaPliku, "rw")) { // Zapis liczby aut do pliku plik.writeInt(auta.length); // zapis kolejnych aut for (Auto auto : auta) { plik.writeUTF(auto.marka); plik.writeUTF(auto.model); plik.writeDouble(auto.pojemnosc); } } catch (IOException e) { return false; } return true; } // Pliki binarne (pliki danych) // Odczyt danych z pliku binarnego, utworzenie tablicy // Założenie: plik rozpoczyna dana typu int, określająca liczbę aut boolean odczytZPlikuBinarnego(String nazwaPliku) { try (RandomAccessFile plik = new RandomAccessFile(nazwaPliku, "rw")) { // Odczyt liczby aut i utworzenie tablicy auta = new Auto[plik.readInt()]; // Odczyt kolejnych aut, ich liczba jest znana for (int i = 0; i < auta.length; ++i) { auta[i] = new Auto(); // Utwórz obiekt auta[i].marka = plik.readUTF(); auta[i].model = plik.readUTF(); auta[i].pojemnosc = plik.readDouble(); } } catch (IOException e) { return false; } return true; } } public class AutaNaPlikiRoznychTypow { public static void main(String[] args) { EwidencjaAut ew = new EwidencjaAut(); System.out.print("Odczyt z pliku tekstowego: "); if (ew.oczytZPlikuTekstowego("auta.txt")) { System.out.println("OK"); ew.pokaz(); } else System.out.println("Błąd"); System.out.print("Zapis do pliku tekstowego: "); if (ew.zapisDoPlikuTekstowego("auta.bak")) System.out.println("OK"); else System.out.println("Błąd"); System.out.print("Zapis do pliku obiektów: "); if (ew.zapisDoPlikuObiektow("auta.obj")) System.out.println("OK"); else System.out.println("Błąd"); System.out.print("Odczyt z pliku obiektów: "); if (ew.odczytZPlikuObiektow("auta.obj")) { System.out.println("OK"); ew.pokaz(); } else System.out.println("Błąd"); System.out.print("Zapis do pliku binarnego: "); if (ew.zapisDoPlikuBinarnego("auta.bin")) System.out.println("OK"); else System.out.println("Błąd"); System.out.print("Odczyt z pliku binarnego: "); if (ew.odczytZPlikuBinarnego("auta.bin")) { System.out.println("OK"); ew.pokaz(); } else System.out.println("Odczyt z pliku obiektów: Błąd"); wyeksportujZAkcyza("akcyza.txt", "auta.bin"); ocenOplacalnosc("akcyza"); } // Dodatkowe przykłady. W tych funkcjach nie korzystamy z tablicy aut ani // obiektów klasy Auto, nie korzystamy z obiektu klasy StringBuilder. // Funkcja odczytuje dane pojazdu z pliku binarnego o nazwie nazwaBinarnego // (format jak w ewidencji aut) i zapisuje do pliku (tekstowego o nazwie // nazwaTekstowego) odczytane dane uzupełnione informacją o akcyzie. // Auta o pojemności poniżej 2000 mają akcyzę 3.1% a auta o pojemności // większej niż 2000 18.65. Procent akcyzy należy dopisać na końcu każdej // linii zapisywanej do pliku tekstowego: // Mercedes SL 3500 18.6 // Fiat 126p 650 3.1 // Liczba aut nie ma być zapisywana do pliku tekstowego. static boolean wyeksportujZAkcyza(String nazwaTekstowego, String nazwaBinarnego) { try ( BufferedWriter plikTxt = new BufferedWriter(new FileWriter(nazwaTekstowego)); RandomAccessFile plikBin = new RandomAccessFile(nazwaBinarnego, "rw") ) { String marka, model, akcyza; double pojemnosc; // Odczyt liczby aut int liczbaAut = plikBin.readInt(); // Odczyt kolejnych aut for (int i = 0; i < liczbaAut; ++i) { marka = plikBin.readUTF(); model = plikBin.readUTF(); pojemnosc = plikBin.readDouble(); akcyza = (pojemnosc < 2000) ? "3.1" : "18.6"; plikTxt.write(marka + " " + model + " " + pojemnosc + " " + akcyza); plikTxt.newLine(); } } catch (IOException e) { return false; } return true; } // Funkcja otrzymuje jako parametr nawę pliku BEZ rozszerzenia (np. "plik"). // Po dopisaniu do tej nazwy rozszerzenia ".txt" (powstaje "plik.txt") funkcja // otwiera do odczytu plik o tej nazwie, każda linia // z pliku ma następujący układ: // <marka> <model> <pojemnosc> <procent akcyzy> // np.: // Mercedes SL 3500 18.6 // Fiat 126p 650 3.1 // Zadaniem funkcji jest zapisanie do drugiego pliku tekstowego raportu // opłacalności, dla przykładu powyżej będzie to: // Mercedes SL drogo // Fiat 126p opłacalnie // Za auto opłacalne uważa się takie, którego pojemność jest mniejsza od 2000. // Nazwa pliku raportu powstaje poprzez doklejenie do nazwy przekazanej // parametrem nazwa rozszerzenia "rpt". Dodatkowo funkcja zapisuje do pliku // binarnego pary pojemnosci akcyza dla każdego auta. Nazwa pliku binarnego // powstaje poprzez doklejenie do nazwy przekazanej parametrem nazwa // rozszerzenia "bin". Rezulataem funkcji ma być liczba aut zklasyfikowanych // jako opłacalne, lub -1 gdzy wystąpoł błąd wejści-wyjścia. // Program używa funkcji split zamiast klasy StringTokenizer. static int ocenOplacalnosc(String nazwa) { String nazwaTekstowego = nazwa + ".txt"; String nazwaBinarnego = nazwa + ".bin"; String nazwaRaportu = nazwa + ".rpt"; int ileOplacalnych = 0; try ( BufferedReader plikTxt = new BufferedReader(new FileReader(nazwaTekstowego)); RandomAccessFile plikBin = new RandomAccessFile(nazwaBinarnego, "rw"); BufferedWriter plikRpt = new BufferedWriter(new FileWriter(nazwaRaportu)) ) { String linia; while ((linia = plikTxt.readLine()) != null) { String[] elementyLinii = linia.split(" "); String marka = elementyLinii[0]; String model = elementyLinii[1]; double pojemnosc = Double.parseDouble(elementyLinii[2]); double akcyza = Double.parseDouble(elementyLinii[3]); plikBin.writeDouble(pojemnosc); plikBin.writeDouble(akcyza); plikRpt.write(marka + " " + model); if (pojemnosc > 2000) plikRpt.write(" drogo"); else { plikRpt.write(" opłacalnie"); ++ileOplacalnych; } plikRpt.newLine(); } } catch (IOException e) { return -1; } return ileOplacalnych; } }