Home > Back-end >  How to read a text file into an array list of objects in Java
How to read a text file into an array list of objects in Java

Time:09-26

I'm currently working on a project and I'm running into a couple of issues. This project involves working with 2 classes, Subject and TestSubject. Basically, I need my program (in TestSubject class) to read details (subject code and subject name) from a text file and create subject objects using this information, then add those to an array list. The text file looks like this:

ITC105: Communication and Information Management
ITC106: Programming Principles
ITC114: Introduction to Database Systems
ITC161: Computer Systems
ITC204: Human Computer Interaction
ITC205: Professional Programming Practice

the first part is the subject code i.e. ITC105 and the second part is the name (Communication and Information Management)

I have created the subject object with the code and name as strings with getters and setters to allow access (in the subject class):

private static String subjectCode;
private static String subjectName;

public Subject(String newSubjectCode, String newSubjectName) {
    newSubjectCode = subjectCode;
    newSubjectName = subjectName;
}

public String getSubjectCode() {
    return subjectCode;
}
public String getSubjectName() {
    return subjectName;
}

public void setSubjectCode(String newSubjectCode) {
    subjectCode= newSubjectCode; 
}

public void setSubjectName(String newSubjectName) {
    subjectName = newSubjectName; 
}

The code I have so far for reading the file and creating the array list is:

public class TestSubject {
   @SuppressWarnings({ "null", "resource" })
   public static void main(String[] args) throws IOException {
    
    File subjectFile = new File ("A:\\Assessment 3 Task 1\\src\\subjects.txt");
    Scanner scanFile = new Scanner(subjectFile);
    
    System.out.println("The current subjects are as follows: ");
    System.out.println(" ");

    while (scanFile.hasNextLine()) {
        System.out.println(scanFile.nextLine());
    }
    
    //This array will store the list of subject objects. 
    ArrayList <Object> subjectList = new ArrayList <>();
    
    //Subjects split into code and name and added to a new subject object.
    String [] token = new String[3];
    
    while (scanFile.hasNextLine()) {
        token = scanFile.nextLine().split(": ");
        String code = token [0]   ": ";
        String name = token [1];
        
        Subject addSubjects = new Subject (code, name);
        
        //Each subject is then added to the subject list array list. 
        subjectList.add(addSubjects);
    }
    
    //Check if the array list is being filled by printing it to the console.
    System.out.println(subjectList.toString());

This code isn't working, the array list is just printing as blank. I have tried doing this several ways including a buffered reader but I can't get it to work so far. The next section of code allows a user to enter a subject code and name, which is then added to the array list as well. That section of code works perfectly, I'm just stuck on the above part. Any advice on how to fix it to make it work would be amazing.

Another small thing:

 File subjectFile = new File ("A:\\Assessment 3 Task 1\\src\\subjects.txt"); //this file path
 Scanner scanFile = new Scanner(subjectFile);

I'd like to know how I can change the file path so that it will still work if the folder is moved or the files are opened on another computer. The .txt file is in the source folder with the java files. I have tried:

 File subjectFile = new File ("subjects.txt");

But that doesn't work and just throws errors.

CodePudding user response:

That is because you have already read through the file

while (scanFile.hasNextLine()) {
    System.out.println(scanFile.nextLine());
}

The contents are exhausted. So when you do

while (scanFile.hasNextLine()) {
    token = scanFile.nextLine().split(": ");

there is no data left.

Remove the first loop or re-open the file.

Or as @UsagiMiyamoto mentions

Or read the line to a String variable, print it, then split it... All in one loop.

CodePudding user response:

I assume you are just beginning with learning Java and hence the below code is probably way too advanced, but it may help others who are trying to do something similar to you and also give you a glimpse of what you will probably learn in future.

The below code uses the following (in no particular order):

More notes after the code.

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public record Subject(String subjectCode, String subjectName) {
    private static final String DELIMITER = ": ";

    private static Path getPath(String filename) throws URISyntaxException {
        URL url = Subject.class.getResource(filename);
        URI uri = url.toURI(); // throws java.net.URISyntaxException
        return Paths.get(uri);
    }

    private static Subject makeSubject(String line) {
        String[] parts = line.split(DELIMITER);
        return new Subject(parts[0].trim(), parts[1].trim());
    }

    /**
     * Reads contents of a text file and converts its contents to a list of
     * instances of this record and displays that list.
     * 
     * @param args - not used.
     */
    public static void main(String[] args) {
        try {
            Path path = getPath("subjects.txt");
            try (Stream<String> lines = Files.lines(path)) { // throws java.io.IOException
                lines.map(Subject::makeSubject)
                     .collect(Collectors.toList())
                     .forEach(System.out::println);
            }
        }
        catch (IOException | URISyntaxException x) {
            x.printStackTrace();
        }
    }
}

A Java record is applicable for an immutable object and it simply saves you from writing code for methods including getters as well as equals, hashCode and toString. (There are no setters since a record is immutable.) It's a bit like Project Lombok. I would say that a Subject is immutable since I don't think the code or name would need to be changed and that's why I thought making Subject a record was applicable.

Running the above code produces the following output:

Subject[subjectCode=ITC105, subjectName=Communication and Information Management]
Subject[subjectCode=ITC106, subjectName=Programming Principles]
Subject[subjectCode=ITC114, subjectName=Introduction to Database Systems]
Subject[subjectCode=ITC161, subjectName=Computer Systems]
Subject[subjectCode=ITC204, subjectName=Human Computer Interaction]
Subject[subjectCode=ITC205, subjectName=Professional Programming Practice]

Regarding

I'd like to know how I can change the file path so that it will still work if the folder is moved

I placed file subjects.txt in the same folder as file Subject.class, which allowed me to use method getResource. Refer to the Accessing resources link, above. Note that this can't be used if

the files are opened on another computer

Alternatively, there are several directories whose paths are stored in System properties including

  • java.home
  • java.io.tmpdir
  • user.home
  • user.dir

CodePudding user response:

what did your debug console said about the exception?

your code works very well in my editor.

code result

and you should code like below if you want to read file through relative path

before ->

new File ("A:\Assessment 3 Task 1\src\subjects.txt");

after ->

new File (".\\subjects.txt");
  • Related