Początki z javą parsowanie pliku "obiektowo"

0

Hej.
Stworzyłam sobie prostą klasę "Studenci" i w klasie do testów w main()

ArrayList<Studenci> studenci = new ArrayList<Studenci>();

. Chciałabym teraz wczytać sobie Imię,Nazwisko każdego studenta z pliku i wstawić do odpowiedniego obiektu Student w ArrayList. Jak prawidłowo obiektowo powinnam to zrobić? Stworzyć klasę np. ReadFile i tam metody np. getLineCounter(); getImie(int id); getNazwisko(int id); ? I potem w main() pętlę typu for(i=0;i<readFile.getLineCounter();i++)

 i po kolei jechać sobie ustawiać? Czy to jest prawidłowe podejście? Tylko wtedy będę musiała w klasie ReadFile utworzyć oddzielne ArrayList<String> na przechowywanie Nazwisk, oddzielne na Imiona tak? Trochę wydajnościowo to kiepsko wygląda chyba :?
Pozdrawiam
1

Ja zawsze robiłem w ten sposób:

import java.util.*;

class Student {
    private String imie;
    private String nazwisko;

    public Student(String i, String n) {
        imie = i;
        nazwisko = n;
    }

    public String toString() {
        return imie + " " + nazwisko;
    }
}


public class Prog {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        ArrayList<Student> studenci = new ArrayList<Student>();

        while (sc.hasNext()) {
            String imie = sc.next();
            String nazwisko = sc.next();
            studenci.add(new Student(imie, nazwisko));
        }

        for (Student s: studenci) {
            System.out.println(s);
        }
    }
}

Później wystarczy wywołać java Prog < studenci.txt zakładając, że plik jest poprawny. Można też zmienić wczytywanie tj. zamienić System.in na np. new File("studenci.txt").

1

@karolinaa to zależy jak te dane przechowujesz. No jeśli to coś na wzór "jedna linia - jeden obiekt" to możesz zrobić konstruktor Student który potrafi zrobić studenta na podstawie takiej linii. Jeśli wymaga ona jakichś cudów na kiju, regexpów etc to mozesz zrobić też jakiegoś helpera który w tej konstrukcji będzie pomagał.

0

@Shalom helper... czyli? hmm... jeszcze mam problemy z tą obiektowością mianowicie: co w przypadku jeśli w przyszłości zmienię sobie format pliku? Załóżmy w pierwszej linijce dodam informację o grupie tych studentów, np plik:

[GRUPA G435C]
[Paweł==Trybson]
[Ania==Duża]
[Wojtek==Jakistam]

Nie chciałabym wtedy rozgrzebywać całego programu.
Czy taka klasa to jest dobry pomysł? zwłaszcza te ArrayList w tej klasie mnie martwią ;/?

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class FileParse {
	private final static Charset ENCODING = StandardCharsets.UTF_8;
	private final Path FilePath;
	private ArrayList<String> names = new ArrayList<String>();
	private ArrayList<String> surnames = new ArrayList<String>();
	private int recordsCounter = 0;


	public FileParse(String FilePath) {
		this.FilePath = Paths.get(FilePath);
	}

	public String getName(int id) {
		return names.get(id);
	}

	public String getSurname(int id) {
		return surnames.get(id);
	}

	public int getRecordCounter() {
		return recordsCounter;
	}

	public final void parse() throws IOException {
		try {
			Scanner scanner = new Scanner(FilePath,ENCODING.name());
			//w pierwszej linijce pojawiła się informacja o grupie, więc dodaję
			processGroupInfo(scanner.nextLine());
			while (scanner.hasNextLine()){
				processRecord(scanner.nextLine());
			}
		} catch(IOException ex) { System.out.println("do ogarnięcia"); }
	}

	protected void processRecord(String Line) {
		Pattern recordPattern = Pattern.compile("\\[(.*)==(.*)\\]");
		Matcher recordMatcher = recordPattern.matcher(Line);
		if(!recordMatcher.find())
			return;
		names.add(recordsCounter, recordMatcher.group(1));
		surnames.add(recordsCounter, recordMatcher.group(2));
		recordsCounter++;
	}

	/* format pliku zmienił się w pierwszej linii dodam informację
	odnośnie nazwy grupy tych studentów np. [M101] dodaję, więc:
	 */

	private String groupInfo;
	public String getGroupInfo() {
		return groupInfo;
	}

	protected void processGroupInfo(String Line) {
		Pattern groupPattern = Pattern.compile("\\[(.*)\\]");
		Matcher groupMatcher = groupPattern.matcher(Line);
		if(!groupMatcher.find())
			return;
		groupInfo = groupMatcher.group(1);
	}

}

potem przy parsowaniu używam np tylko:

FileParse test = new FileParse("test.txt");
test.parse();
System.out.println(test.getGroupInfo());
for(i=0;i<test.getRecordCounter();i++)
      records.add(i,new Student(test.getSurname(i),test.getName(i)));

PS
proszę nie zwracać uwagi na głupie nazwy zmiennych czy brak obsługi wyjątków jestem początkująca i chodzi tylko oto jak podejść do takiego zagadnienia prawidłowo.
a i obiekt Student do którego wczytuje Imię i Nazwisko z pliku ma jeszcze inne pola, np. Numer Indeksu - ale to pobieram już z innego miejsca.

0

Moim zdaniem takie rozwiązanie jest mega słabe. To już lepiej by było gdyby ten twój parser potrafił jednak sam tworzyć tych studentów, bo w zasadzie to jest taki "transformer" który przetwarza jedną reprezentację obiektów (tekstową w pliku) na inną.

0

Najlepiej w tym celu skorzystać z normalnej bazy danych albo mechamizmu serializacji (ObjectInputStream i ObjectOutputStream). Ewentualnie bibliotekę Kryo, która ponoć ma znacznie wyższą wydajność.

0

@Shalom a mogłabym od razu w tym "parserze" tworzyć ArrayList obiektów klasy Student? i potem zwrócić po prostu tak żebym mogła na tym operować w main()?
@niezalogowany - na razie to chciałam nauczyć się podstaw :)

1

Moim zdaniem, lepiej zrobić osobną klasę, która zawiera dane o studencie, tak jak w moim poprzednim poście. Ta klasa powinna być niezależna od rodzaju wczytywania, bo mogą być różne metody (z pliku, z bazy danych). Helper w tym przypadku jest pomocny i oznacza, aby zrobić dodatkową klasę która wczytuje dane z pliku i zwraca listę studentów. Gdy później będziesz potrzebowała obsłużyć inny format pliku, wystarczy napisać kolejny helper.

0

heh ,dobra mam jeszcze dwa pytania (dopiero teraz mam znowu czas na Javę);

  1. Mój projekt składa się z kilku osobnych plików (*.java). W osobnym pliku mam klasę Student, Czy klasę "StudentsFileHelper" tak samo mogę umieścić w osobnym pliku i zrobić ją public?
  2. Czy do "parsowania" z pliku informacji na temat tego pliku (1 wiersz np. Autor, Data spisu), powinnam stworzyć osobną klasę? Np. InfoFileHelper?
[Jan Nowak - 15.01.2014]
[Paweł==Trybson]
[Ania==Duża]
[Wojtek==Jakistam]

Przejrzałam przed chwilą sobie pobieżnie Single Responsibility Principle, Low Coupling stąd http://www.e-point.pl/_fileserver/item/1500355 i chcę się po prostu upewnić czy prawidłowo obiektowo do tego podchodzę. tak żeby sprzyjało to przyszłej skalowalności aplikacji.
Pozdrawiam i dzieki

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