Zaprezentuję teraz drugi wariant zapisu i odczytu danych. Język Java oferuje dodatkowo obiekty zdolne do przetwarzania danych zapisanych w pliku tekstowym. Tutaj procedura jest zdecydowanie bardziej rozbudowana i uprzedzam, że może sprawiać duże trudności w rozumieniu, gdyż kod przeze mnie prezentowany będzie od razu zaopatrzony w funkcje których mogliście nie widzieć jeszcze na własne oczy. Skoro już Państwa uprzedziłem, przechodzimy do rozpoczęcia tematu. Zapis i odczyt z pliku tekstowego.

ZAPIS I ODCZYT Z PLIKU. CZYM SIĘ RÓŻNI OD SERIALIZACJI?

W pierwszych słowach mojego wywodu chcę wspomnieć o istotnej rzeczy odnośnie dokonania wyboru "kiedy jedno, a kiedy drugie". Rezygnujemy z serializacji obiektów wówczas gdy nasz program ma obsługiwać dane wejściowe wykraczające poza język Java. Jakbyśmy byli w stanie zaimportować takie dane na przykład z programu napisanego w C++? Ja jakoś sobie tego nie wyobrażam. Jedyny sposób to właśnie ten o którym jest teraz mowa, czyli eksport do pliku o formacie uniwersalnym, który nie dotyczy jedynego języka. Wtedy otwarcie takiego pliku staje się możliwe i mamy zaletę niniejszego rozwiązania.

Wadą jest możliwość edycji w zwykłym notatniku. Zapis i odczyt z pliku to przecież podstawowe funkcje edytorów tekstu. Są dostępne warianty szyfrowania danych tekstowych, ale to już wyższa szkoła jazdy nieznana amatorom. Nie czas na takie rewelacje, zatem przedstawię na razie sam proces zapisywania i odczytywania danych z pliku ".txt".

  • KLASA "Main"
public class Main
{
	public static void main(String[] args)
	{
		new TextIO();
	}
}
  • KLASA "TextIO"
import javaX.io.*;
import javaX.util.ArrayList;

public class TextIO
{
	private static final String SAVE_FILENAME = "save.txt";

	private ArrayList<Point> points = new ArrayList<>();

	public TextIO()
	{
		createInstances();

		try
		{
			writeToFile();
			//readFromFile();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}

		printPoints();
	}

	private void createInstances()
	{
		points.add(new Point());
		points.add(new Point(8, 6));
		points.add(new Point(14, 13));
	}

	private void writeToFile() throws IOException
	{
		File file = new File(SAVE_FILENAME);
		FileWriter fw = new FileWriter(file);
		BufferedWriter bw = new BufferedWriter(fw);

		for (Point point : points)
		{
			bw.write(point.saveFormat());
			bw.newLine();
		}

		bw.close();
	}

	private void readFromFile() throws IOException
	{
		File file = new File(SAVE_FILENAME);
		FileReader fr = new FileReader(file);
		BufferedReader br = new BufferedReader(fr);
		String data;

		while ((data = br.readLine()) != null)
		{
			String[] coordinates = data.split(",");
			int x = Integer.parseInt(coordinates[0]);
			int y = Integer.parseInt(coordinates[1]);
			Point newPoint = new Point(x, y);

			points.add(newPoint);
		}
	}

	private void printPoints()
	{
		for (Point point : points)
		{
			System.out.println(point);
		}
	}
}
  • KLASA "Point"
public class Point
{
	private int x, y;

	public Point()
	{
		this(0, 0);
	}

	public Point(int x, int y)
	{
		setPosition(x, y);
	}

	public void setPosition(int x, int y)
	{
		this.x = x;
		this.y = y;
	}

	public String saveFormat()
	{
		return x + "," + y;
	}

	@Override
	public String toString()
	{
		return "(" + x + ", " + y + ")";
	}
}

Informuję, że w importach są zawarte literówki z powodu niemożności zapisania artykułu przez Joomlę (musi być usunięta litera "X"!).

Zachowałem tę samą strukturę, aczkolwiek z drobnymi zmianami. Po pierwsze, skorzystałem tym razem z kolekcji "ArrayList" będącej najbardziej podstawową w języku Java. Zapis i odczyt z pliku aby się udał w pełni, musi korzystać z listy lub tablicy. Główne punkty programu też uległy zmianie i czas na spory zastrzyk wyjaśnień tych obu metod ("writeToFile" oraz "readFromFile"). Czyli zapis i odczyt z pliku.

ZAPIS DO PLIKU - DOKŁADNE WYJAŚNIENIE

Metoda zapisująca do pliku korzysta z trzech zmiennych lokalnych. Pierwsza ("File") tworzy nowy plik o podanej nazwie wraz ze ścieżką do niego. Druga zmienna to typ "FileWriter" umożliwiający wykonywanie operacji na strumieniach znaków. Pamiętacie w poprzednim przykładzie nazwę "FileInputStream" i "FileOutputStream"? To są "bliźniaki" sterujące również strumieniami, ale bajtów zamiast znaków. Dlatego właśnie "zmielone" obiekty wyświetlały same dyrdymały w notatniku. Ostatnia mniej znana klasa to "BufferedWriter" stanowiąca duże "wspomaganie" dla strumienia znaków posiadająca dużo więcej możliwości. Ona sama w sobie nie jest wymagana, aczkolwiek stanowi pomocny dodatek do zapisywania danych.

Dalej mamy pętle "for", aczkolwiek o innym charakterze niż ta podstawowa pętla "for", którą znamy z języka C. To jest tak zwana "pętla rozszerzona" dzięki której możemy dużo wygodniej obsługiwać wszelkie tablice i listy. W Javie jest ona często wykorzystywana, a ja zdążyłem umieścić o niej osobny artykuł. W środku niej wywołujemy metodę z "BufferedWriter" o nazwie "write" dopisującą tekst do pliku jako zwróconą wartość z funkcji znajdującej się w klasie przeznaczonej do tworzenia punktów w przestrzeni 2D.

Klasa "Point" posiada dodatkową metodę formatującą współrzędne dla zapisywanych danych. Powodem jest obsługa odczytywania. Znajduje się tam pętla "while", która zarządza przetwarzaniem pliku tekstowego linijka po linijce. Gdybyśmy umieścili format zgodny z funkcją "toString", to musielibyśmy zaprogramować system w taki sposób, aby "przeskakiwał" znak nawiasu oraz znak odstępu tuż po przecinku. Zapis i odczyt pliku wymaga szwajcarskiej precyzji w kwestii "chodzenia" znak po znaku.

Po zapisaniu wartości w danym wierszu, każemy następnym poleceniem przenieść się do nowego wiersza i w ten sposób każdy osobny wiersz przechowuje jedną parę dwóch współrzędnych. Na końcu jest zamknięcie strumienia, które stanowi nasz obowiązek. Zapis i odczyt z pliku zawsze musi się kończyć zamknięciem pliku na którym operujemy!

ODCZYT Z PLIKU - DOKŁADNE WYJAŚNIENIE

Teraz zerkamy na "readFromFile". Występują te same zmienne tylko korzystamy teraz z klas przeznaczonych do odczytu strumieni danych ("FileReader" i "BuffereredReader"). O wiele ciekawsza jest pętla "while", która weryfikuje każdy następny wiersz tekstu czy nie jest pusty ("null"). Ważne jest to aby wiedzieć, że metoda "readLine" pobiera wiersz tekstu przesuwając się w stronę kolejnego wiersza i zatrzymując się na nim aż trafi na sam koniec. W środku niej mamy tablicę pobierającą nasze dwie liczby całkowite za pomocą kolejnej metody, "split".

"split" zwraca tablicę typu "String" dzieląc jeden łańcuch tekstu na kilka fragmentów sugerując się podanym znakiem (tzw. "separatorem"). W naszym przypadku jest to przecinek, a zatem znak przecinka spowoduje "podział" tekstu. Następnie po wyodrębnieniu pożądanych współrzędnych, konwertujemy łańcuch na liczbę przy pomocy "parseInt" z klasy "Integer". Następnie tworzymy nową instancję typu "Point", przypisujemy nasze liczby i wreszcie dodajemy nasz obiekt do listy.

Na koniec taka uwaga, że odczytując dane i wprowadzając obiekty do listy, niepotrzebne jest wywołanie funkcji dodające przykładowe punkty. To jest tylko konieczne przy pierwszym zapisie, ale przy wczytywaniu możecie to sobie zakomentować.

Zapis i odczyt z pliku tekstowego w języku Java

Oto efekt zapisu danych do pliku tekstowego. Dzięki formatowaniu tekstu w postaci jednej pary liczb na wiersz, dużo łatwiej będzie przebiegać odczyt.

Strasznie duże wyszły mi te wyjaśnienia, sam się takich nie spodziewałem. Najważniejsze, żebyście już rozumieli na czym to polega. Jednak musicie sobie dać znacznie więcej czasu na przemyślenie tego. Występuje tu dużo funkcji, które dla większości z Was mogą być jeszcze obce. Zapis i odczyt z pliku jest uważany za temat zaawansowany, dlatego też możecie zabrać się za niego dużo później.


Teraz dopiero zakończymy ten wpis. Podziękowania i gratulacje dla każdego, który to wszystko przeczytał ze zrozumieniem.

PODOBNE ARTYKUŁY