nus-cs2103-AY2425S1 / forum

12 stars 0 forks source link

Error loading tasks from file in jar #328

Closed tayxuenye closed 1 day ago

tayxuenye commented 1 day ago

When I copied and pasted my jar file to downloads, the app runs but is unable to load file. Screenshot 2024-09-18 163329 Does anyone have an idea why? The file path passed in is data/optimus.txt . It works fine when in the original iP directory.

package optimus;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;

// Let ChatGPT check and suggest comments and JavaDocs according to CS2103T style guide
/**
 * Handles loading and saving tasks to and from a file.
 */
public class Storage {
    private String filePath; // File path for storing the task data
    private Ui ui;

    /**
     * Constructs a Storage object with the specified file path.
     *
     * @param filePath The file path where tasks are stored.
     */
    public Storage(String filePath, Ui ui) {
        this.filePath = filePath;
        this.ui = ui;
    }

    /**
     * Loads tasks from the file if it exists.
     * If the file or directory does not exist, create them.
     * This method was partially inspired by code examples provided by ChatGPT and W3Schools.
     * Solution below inspired by https://www.w3schools.com/java/java_files_create.asp
     * ChatGPT suggested to catch IOException
     * ChatGPT suggested how to shorten method
     *
     * @return The list of tasks loaded from the file.
     */
    public ArrayList<Task> loadTasks() throws IOException {
        ArrayList<Task> taskList = new ArrayList<>();
        File directory = new File("data");
        File file = new File(filePath);

        if (!directory.exists()) {
            directory.mkdir();
        }

        if (!file.exists()) {
            file.createNewFile();
            ui.showToUser("Created new data file optimus.txt");
            return taskList;
        }
        // Read tasks from the file
        try (Scanner scanner = new Scanner(file)) {
            while (scanner.hasNextLine()) {
                String line = scanner.nextLine();
                try {
                    Task task = parseTaskFromLine(line);
                    taskList.add(task);
                } catch (OptimusException | ArrayIndexOutOfBoundsException e) {
                    // Suggested by ChatGPT
                    ui.showToUser("Error loading task: " + e.getMessage());
                }
            }
            ui.showToUser("Loaded tasks from file optimus.txt");
        }
        return taskList;
    }

    /**
     * Parses a task from a line of text.
     *
     * @param line The line of text representing the task.
     * @return The parsed Task object.
     * @throws OptimusException If there is an issue with parsing.
     */
    private Task parseTaskFromLine(String line) throws OptimusException {
        String[] parts = line.split("\\|");
        String taskType = parts[0].trim();
        boolean isDone = parts[1].trim().equals("1");

        Task task;
        if ("T".equals(taskType)) {
            task = new Todo(parts[2].trim());
        } else if ("D".equals(taskType)) {
            task = new Deadline(parts[2].trim(), parts[3].trim());
        } else if ("E".equals(taskType)) {
            task = new Event(parts[2].trim(), parts[3].trim(), parts[4].trim());
        } else {
            throw new OptimusException("Invalid task type: " + taskType);
        }
        task.isDone = isDone;
        return task;
    }
}
damithc commented 1 day ago

@tayxuenye can you share the jar file, so others can try it too?

RezwanAhmed123 commented 1 day ago

Ok im not sure if this is definitely the issue but:

        File directory = new File("data");
        File file = new File(filePath);

        if (!directory.exists()) {
            directory.mkdir();
        }

        if (!file.exists()) {
            file.createNewFile();
            ui.showToUser("Created new data file optimus.txt");
            return taskList;
        }

In your main class u already defined the filepath already and then here u are defining it differently here to check if it exists. So maybe, there is some bug which causes duplicated files (notice that the directory is defined separately before the file when in filepath it comes together) causing your storage class to be confused when it needs to create its own file. So it might be the reason why u are facing it outside of ur repo (because u need to create it there).

I would suggest changing the above code to the following:

        File f = new File(filepath);
        f.getParentFile().mkdirs();
        f.createNewFile();
        f.exists();

hopefully it works for you!

tayxuenye commented 1 day ago

@tayxuenye can you share the jar file, so others can try it too?

@tayxuenye can you share the jar file, so others can try it too?

Prof, unfortunately github does not support sending jar files

WinstonJin commented 1 day ago

Hi I'm also getting this issue. I'm using a Macbook and it seems that this problem only occurs when trying to run from the jar file. If I do the ./gradlew run on the IntelliJ terminal, it works fine and I can read the previous safe file. But if I do ./gradlew clean shadowJar and go to the directory and run the following, I get the error message:

My input in the terminal

java -jar Winde.jar

The error message I get

Error in creating fileNo such file or directory
Error Loading Tasks to File: ../src/main/java/windebot/Winde.java (No such file or directory)
damithc commented 1 day ago

Prof, unfortunately github does not support sending jar files

@tayxuenye you can either zip it up first and attach it to a post here, or create a release in GitHub and upload the jar file to the release.

damithc commented 1 day ago

../src/main/java/windebot/Winde.java

@WinstonJin

  1. You can't expect these folders to be present relative to the location of the jar file. That's why the code works when you run it using source files but not when you run it from the jar file (because the path is specified relative to the source file, not the jar file).
  2. This is a Windows way of specifying paths. It is better to use an OS-independent way to specify paths.
  3. Why are you putting tasks in a .java file?

The simplest relative path you can use is something like Winde.txt (which expects the file to be in the same folder as the jar file). Of course if the file is missing, your code needs to create it first.

WinstonJin commented 1 day ago

Oh my bad prof, I copied the wrong error code for this

Error in creating fileNo such file or directory
Error Loading Tasks to File: ../src/main/java/windebot/WindeTasks.txt (No such file or directory)

So I tried changing the file path to WindeTasks.txt instead of the ../src/main/java/windebot/WindeTasks.txt and I get a long error message:

Caused by: java.lang.NullPointerException: Cannot invoke "java.io.File.mkdirs()" because the return value of "java.io.File.getParentFile()" is null
    at windebot.History.load(History.java:60)
    at windebot.Winde.<init>(Winde.java:40)
    at gui.Main.<init>(Main.java:17)
    ... 11 more

This is the line 60 code in History:

            if (!file.exists()) {
                file.createNewFile();
                file.getParentFile().mkdirs(); // line 60
                file.createNewFile();
                // file.exists();
damithc commented 1 day ago

@WinstonJin let's not hijack this issue to discuss your case. Can you open another issue for it?

tayxuenye commented 1 day ago

Ok im not sure if this is definitely the issue but:

        File directory = new File("data");
        File file = new File(filePath);

        if (!directory.exists()) {
            directory.mkdir();
        }

        if (!file.exists()) {
            file.createNewFile();
            ui.showToUser("Created new data file optimus.txt");
            return taskList;
        }

In your main class u already defined the filepath already and then here u are defining it differently here to check if it exists. So maybe, there is some bug which causes duplicated files (notice that the directory is defined separately before the file when in filepath it comes together) causing your storage class to be confused when it needs to create its own file. So it might be the reason why u are facing it outside of ur repo (because u need to create it there).

I would suggest changing the above code to the following:

        File f = new File(filepath);
        f.getParentFile().mkdirs();
        f.createNewFile();
        f.exists();

hopefully it works for you!

Ok im not sure if this is definitely the issue but:

        File directory = new File("data");
        File file = new File(filePath);

        if (!directory.exists()) {
            directory.mkdir();
        }

        if (!file.exists()) {
            file.createNewFile();
            ui.showToUser("Created new data file optimus.txt");
            return taskList;
        }

In your main class u already defined the filepath already and then here u are defining it differently here to check if it exists. So maybe, there is some bug which causes duplicated files (notice that the directory is defined separately before the file when in filepath it comes together) causing your storage class to be confused when it needs to create its own file. So it might be the reason why u are facing it outside of ur repo (because u need to create it there).

I would suggest changing the above code to the following:

        File f = new File(filepath);
        f.getParentFile().mkdirs();
        f.createNewFile();
        f.exists();

hopefully it works for you!

Seems to run ok now. Thank you so much!