Daniel
Daniel

Reputation: 673

Saving data to a file doesn't behave as expected

I have a simple project where I created a Store with customers, products and employees. Each is represented by a Class of course and I also have a CSV file for each one of them to be able to load data from and save data to it.

I'm facing issues where the file reading/writing is working, but not really. For example, I have the ability to save each file individually so if for instance I want to create a new customer, I'd save it to the list and then to the file. Issue is, once I do it for another Class (i.e if I create a new employee) and then save it again, the customer file object I saw in the CSV earlier is deleted. BUT, once I add a new object again, that same object reappears again. Hope you can somehow understand, but here is a more detailed view:

customer.csv is empty:

enter image description here

Me creating a new customer:

enter image description here

enter image description here

Created and saved to CSV:

enter image description here

Now, if I go to the other menu, and click on "Save all data" that jon snow customer object will be gone. Then if I create a new customer, then it will be added to the CSV file, along with the jon snow I added earlier. So why is it gone in the first place?

So here is the whole file reader/writer code I'm using:

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.util.ArrayList;
import java.io.IOException;
import java.util.List;
import java.util.Scanner;

class CSV {

    static void CreateFile(String filename) { //Create new file
        try {
            File fileToCreate = new File(filename);
            if (fileToCreate.createNewFile()) {
                System.out.println("File created sucessfully: " + fileToCreate.getName());
            }
        } catch (IOException e) {
            System.out.println("Cannot create file!");
        }
    }

    static void ReadFile(String path_and_filename){
        try {
            File fileToRead = new File(path_and_filename);
            Scanner myReader = new Scanner(fileToRead);
            System.out.println("Reading file "+path_and_filename+" :");
            while (myReader.hasNextLine()) {
                String data = myReader.nextLine();
                System.out.println(data);
            }
            myReader.close();
            System.out.println();
        } catch (FileNotFoundException e) {
            System.out.println("There is no such file "+"\"path_and_filename\""+".\n");
        }
    }

    // The StringBuilder in Java represents a mutable sequence of characters.
    // Java's built in String class is not mutable.
    static void saveArrayListToFile(List<Output> listToSave, String fileName, String sep) throws Exception {
        StringBuilder ans = new StringBuilder();
        for (Output record : listToSave) {
            ans.append(record.createOutput());
            ans.append(sep);
        }
        saveStringToFile(ans.toString(), fileName);
        System.out.println("\nData saved to "+ fileName);
    }

    static void saveArrayListToFile1(ArrayList<String> listToSave, String fileName, String sep){
        StringBuilder ans = new StringBuilder();
        for (Object record : listToSave) {
            ans.append(record.toString());
            ans.append(sep);
        }
        saveStringToFile(ans.toString(), fileName);
        System.out.println("\nList was saved to file "+fileName+"\n");
    }

    static void saveStringToFile(String data, String fileName){
        BufferedWriter bufferedWriter=null;
        try {
            bufferedWriter = new BufferedWriter(
                    new FileWriter(fileName,false));
            bufferedWriter.write(data);
        } catch (IOException e) {
            System.out.println("Cannot write to file");
        } finally {
            try {
                bufferedWriter.close();
            } catch (IOException e) {
                System.out.println("Cannot write to file");
            }
        }
    }
}

When I'm creating a new customer, I call it from a menu and it looks like this:

            switch (selection) {
                case 1:
                    try {
                        System.out.println("You're registering as a new customer");
                        String custID = ObjectIDs.generateID();
                        System.out.println("Enter first name:");
                        String firstName = sc.next();
                        System.out.println("Enter last name:");
                        String lastName = sc.next();
                        st.newCustomer(custID, firstName, lastName);
                        st.saveCustomersList();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;

the saveCustomerList() function is this:

@SuppressWarnings("unchecked")
    void saveCustomersList() throws Exception {
        CSV.saveArrayListToFile((List<Output>)(List<?>) customers, CUSTOMERS_FILE_PATH,"\n");
    }

And then the functions calls saveArrayListToFile() to save it.

The behavior is the same with Product and Employee projects, so I randomly chose to show how it acts when creating a new Product.

I hope I added enough information. If needed, I can paste more code in but I already feel it's very cluttered. Hopefully it's ok.

Thank you very much :)

Upvotes: 0

Views: 66

Answers (2)

Cedric
Cedric

Reputation: 446

In addition to pafau k. I would like to add some things at least I would do differently...

First of all:

Things that can cause errors or unexpected behaviour:

Everything below is in saveStringToFile

  • Like already pointed out the Initialisation of the BufferedWriter: It should be initialized like this: bufferedWriter = new BufferedWriter(new FileWriter(filename, true)); This puts the File into appending mode (if you want to append to a file you can also get rid of the boolean (second argument) entirely because appending is standard: new FileWriter(filename))
  • If for some case the Creation of the BufferedWriter failed you will still have a null-pointing object as bufferedWriter. This however means that you will be surprised with a NullPointerException in your finally block. To prevent this first of all do a check in your finally block:

    if (bufferedWriter != null) {
        // Close your bufferedWriter in here
    }
    

    Also, if you run into an error you will likely be presented with the same error message twice.


Now cosmetics:

Things that I would write differently for aesthetic reasons:

  • Java methods (and static "methods") are always starting with a small letter :) This means it should be public static void createFile() for example or static void readFile()
  • variables and parameters of methods do not contain seperators like _ but instead if you want to make it more readable you start with a small letter and for each seperation you use a capital letter for that: e.g. String thisIsAVeryLongVariableWithALotOfSeperations = "Foo";
  • The generic types in saveArrayListToFile1() work like a placeholder. So you declare ArrayList<String> listToSave so you don't need a cast in the following for-loop: You can simply write:

    for (String record : listToSave) {
        ans.append(record);
        ans.append(sep);
    }
    

I hope this fixes all errors or complications. :)

Upvotes: 0

pafau k.
pafau k.

Reputation: 1687

At the moment it's hard to say, as one can only hypothesise as to what happens when you click on "Save all data". There are some weird things (what is saveArrayListToFile and saveArrayListToFile11? Why does one declare an exception? When are these called?).

Having said that, look at the actual file writing method saveStringToFile, it says:

bufferedWriter = new BufferedWriter(new FileWriter(fileName,false));

This false there means 'do not append to file, rewrite it from scratch'. So each time you call it, file contents are discarded and replaced from what you provide to the method call. So my somewhat educated guess would be:

  1. You save customer one to file (gets cleared, customer 1 written) and append the customer to a list of customers (that's my guess)
  2. You save customer two to file (file gets cleared, so only customer 2 is saved), you add to list to customers (do you?)
  3. Then you choose 'save all' which gets list of customers, and save them in one go, a single call to the method. The file is cleared, all customers are saved.

But it's all guessing. Try creating a minimal, reproducible example

Upvotes: 2

Related Questions