I want to read the values from custom text file in Java.
Here is my text file shown below:
Classroom1
Student1 Name, Student1 Surname , Student1 Age
Student2 Name, Student2 Surname , Student2 Age
Student3 Name, Student3 Surname , Student3 Age
Student4 Name, Student4 Surname , Student4 Age
...
Classroom2
Student1 Name, Student1 Surname , Student1 Age
Student2 Name, Student2 Surname , Student2 Age
Student3 Name, Student3 Surname , Student3 Age
Student4 Name, Student4 Surname , Student4 Age
...
Classroom3
...
I tried to implement some coding stuff but I couldn't handle with the process.
I want to add all students to each classroom. I thought to use Map<String,List<Student>>
to handle with that but I couldn't implement the process of reading the values.
How can I do that?
Here is the code snippet shown below.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in); // detect inputs from the terminal input, System.in
List<Student> students;
while(in.hasNextLine()) { // while the scanner has a next line
in.nextLine();
String[] s = in.nextLine().split(",");
students.add(new Student(s[0], s[1], s[2]));
}
}
public class Student {
public String name;
public String surname;
public int age;
public Student(String name, String surname, int age) {
// ...
}
}
}
CodePudding user response:
You wrote in your question:
I want to add all students to each classroom. I thought to use Map<String,List>
I assume that the Map
key is the name of the classroom, for example Classroom1 that appears on a line, by itself, in the sample file (named students.txt) in your question. And the Map
value is the List
of students in that classroom.
Consider the following:
(Notes after the code.)
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
public class Student {
private String name;
private String surname;
private int age;
public Student(String name, String surname, int age) {
this.name = name;
this.surname = surname;
this.age = age;
}
public static void main(String[] args) {
Path source = Paths.get("students.txt");
try (Scanner s = new Scanner(source)) {
Map<String, List<Student>> classrooms = new HashMap<>();
String classroom = "";
while (s.hasNextLine()) {
String line = s.nextLine();
if (line.startsWith("Classroom")) {
classroom = line;
classrooms.put(classroom, new ArrayList<Student>());
}
String[] fields = line.split(",");
if (fields.length == 3) {
try {
int age = Integer.parseInt(fields[2].trim());
Student stud = new Student(fields[0].trim(), fields[1].trim(), age);
List<Student> students = classrooms.get(classroom);
students.add(stud);
}
catch (NumberFormatException xNumberFormat) {
// Ignore
}
}
}
}
catch (IOException xIo) {
xIo.printStackTrace();
}
}
}
- You don't need a separate class with just a
main
method, in order to run your program. ClassStudent
can also contain amain
method. - The code in your question tries to get values from the user rather than reading the students.txt file.
- According to the sample data in your question, there are spaces around the commas on some of the lines in the students.txt file. Hence the calls to method trim.
- The above code uses try-with-resources.
- You need to convert the last field of the lines containing student details from a
String
to anint
. Hence the call to methodparseInt
. That method may throwNumberFormatException
and therefore the call is inside a try-catch. If theString
cannot be converted to anint
, then I simply ignore that line. You may wish to do something else. I couldn't ascertain from your question how you want to handle invalid lines in the student.txt file, i.e. lines that don't contain the expected data. - Method
get
, of interfacejava.util.Map
, may return null. The above code does not handle that situation because it should not occur. You may need to modify the above code such that it does handle the situation where methodget
returns null.
CodePudding user response:
I'm not sure if that answer is exactly what you want look for, but i've done my best to guess what you may want to do :)
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
public class Main {
public static final String FILE_PATH = "src/students.txt";
public static final String STUDENT_FIELDS_SEPARATOR = ",";
public static final String CLASSROOM_SEPARATOR = "...";
public static void main(String[] args) {
Map<String, List<Student>> classroomMap = parseStudentsFile();
System.out.println(classroomMap);
}
private static Map<String, List<Student>> parseStudentsFile() {
try (BufferedReader reader = new BufferedReader(new FileReader(FILE_PATH))) {
AtomicReference<String> currClassroom = new AtomicReference<>("");
return reader.lines().map(line -> {
String[] splitLine = line.split(STUDENT_FIELDS_SEPARATOR);
if (splitLine.length == 1 && !splitLine[0].equals(CLASSROOM_SEPARATOR)) {
currClassroom.set(splitLine[0]);
} else if (splitLine.length == 3) {
try {
return Map.entry(currClassroom, new Student(splitLine[0].strip(), splitLine[1].strip(), Integer.parseInt(splitLine[2].strip())));
} catch (NumberFormatException e) {
System.out.println("NumberFormatException - line ignored, cannot parse: " line);
return null;
}
} else return null;
return null;
})
.filter(Objects::nonNull)
.collect(Collectors.groupingBy(
o -> o.getKey().toString(),
Collectors.mapping(Map.Entry::getValue, Collectors.toList())));
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
public class Student {
private final String name;
private final String surname;
private final int age;
public Student(String name, String surname, int age) {
this.name = name;
this.surname = surname;
this.age = age;
}
@Override
public String toString() {
return "Student{"
"name='" name '\''
", surname='" surname '\''
", age=" age
'}';
}
}
students.txt
Classroom1
Student1 Name, Student1 Surname , 1
Student2 Name, Student2 Surname , 2
Student3 Name, Student3 Surname , 3
Student4 Name, Student4 Surname , 4
...
Classroom2
Student1 Name, Student1 Surname , 1
Student2 Name, Student2 Surname , 2
Student3 Name, Student3 Surname , 3
Student4 Name, Student4 Surname , 4
...
output
{Classroom2=[Student{name='Student1 Name', surname='Student1 Surname', age=1}, Student{name='Student2 Name', surname='Student2 Surname', age=2}, Student{name='Student3 Name', surname='Student3 Surname', age=3}, Student{name='Student4 Name', surname='Student4 Surname', age=4}], Classroom1=[Student{name='Student1 Name', surname='Student1 Surname', age=1}, Student{name='Student2 Name', surname='Student2 Surname', age=2}, Student{name='Student3 Name', surname='Student3 Surname', age=3}, Student{name='Student4 Name', surname='Student4 Surname', age=4}]}
CodePudding user response:
Usually you do want to read this sort of data from a specific type of file, like .xml or something like that. In your case, you have to find a way to get rid of all the spaces and additional characters and extract from each line [Name, Surname, Age]. Here is the solution:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;
public class ReadFile {
public static void main(String[] args) throws FileNotFoundException {
File file = new File(filePath);
Scanner in = new Scanner(file);
ArrayList<Student> students = new ArrayList<Student>();
while (in.hasNextLine()) { // while the scanner has a next line
String[] s = in.nextLine().split(",");
if (!s[0].equals("...") && !s[0].contains("Classroom")) {
String[] age = s[2].split(" ");
String[] name = s[0].split(" ");
String[] surname = s[1].split(" ");
students.add(new Student(name[1], surname[2],Integer.parseInt(age[2])));
}
}
for (Student student : students) {
System.out.println(student.toString());
}
}
public static class Student {
public String name;
public String surname;
public int age;
public Student(String name, String surname, int age) {
this.name = name;
this.surname = surname;
this.age = age;
}
@Override
public String toString() {
return "Student{"
"name='" name '\''
", surname='" surname '\''
", age=" age
'}';
}
}
}