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;
}
}