How do I write and delete Objects from a RandomAccessFile? - java

I am currently working on a school project for which I need to save my data to a RandomAccessFile. I figured that this is by far not the most efficient way, but I have to do it. Note: I have to use the RandomAccessFile class.
I understand how I can save simple strings and int created in the main method to a file, but I am having trouble transferring this knowledge onto my own program.
I have 4 different classes, i.e. Database, Group, Student, Rehearsal. The Database class lets you add groups to a linked list of groups. To each group, you can then add students (see below) as well as rehearsal dates (its a theatre management program). These are added to linkedlist<Student> and linkedlist<Rehearsal> respectively.
This is my addStudent method in the Group class that adds a student to the linkedlist of a group that was created.
public void addStudent(int id, String firstname, String lastname) throws IOException {
Student newstudent = new Student(id, firstname, lastname);
if (!Students.contains(newstudent)) {
Students.add(newstudent);
} else
JOptionPane.showMessageDialog(null, "Student with ID " + id
+ " already exists in group!", "Error",
JOptionPane.WARNING_MESSAGE);
}
How do I let the method automatically write the student object to the file when it is executed?
This is my removeStudent method:
public void removeStudent(int id) {
if (!Students.remove(new Student(id, null, null))) {
JOptionPane.showMessageDialog(null, "Student with ID[" + id
+ "] not present. System unchanged.");
}
}
Pretty much the same question, how can I then delete a specific object from the file when the method is executed. If you could me help me out on that as well, that would be great :)

override the toString() method of object class in the way you want to write to the file!
then loop using foreach over the linkedlist and call toString() on student object and write to file
example:
fileOutputStream outStream=newFileOutputStream("../RandomAccessFile");//path where you want to create file
foreach(Student s in linkedlist)
{
outStream.println(s.toString()+"/n");
}

You can't delete anything from a RandomAccessFile except by implementing some file protocol that your code understands, for example filling a record with nulls, assuming your file has records, and assuming that all-nulls (or whatever) is not a legal record value. Or implement a byte header on each record such that 1 means present and 0 means deleted, or vice versa.

Related

is different data types like string int and array in the same csv file can be readable in java?

this is the model to follow for the assignment.
I have created java classes as you can see down below.
class BookerPrize{
private int year;
book winner;
List<book> shortlist;
List<String> panel;
String chairPerson;
public BookerPrize( int year,book winner, List<book> shortlist, List<String> panel, String chairPerson) {
super();
this.winner = winner;
this.shortlist = shortlist;
this.panel = panel;
this.year = year;
this.chairPerson = chairPerson;
}
public book getwinner() {
return winner;
}
public List<book> getshortlist() {
return shortlist;
}
public List<String> getpanel() {
return panel;
}
public int getYear() {
return year;
}
public String getchairPerson() {
return chairPerson;
}
#Override
public String toString() {
return "Winner : " + " [ " + winner.getTitle() + " " + winner.getTitle() + " " + winner.getTitle() + " ] " + "\n" + "year : " + year + "\n" + "chair man : " + chairPerson + "\n";
}
}
and here is the book.java class
public class book {
private String title,author,publisher;
public book(String title, String author, String publisher) {
this.title = title;
this.author = author;
this.publisher = publisher;
}
public String getTitle() {
return title;
}
public String getauthor() {
return author;
}
public String getpublisher() {
return publisher;
}
}
I am a little confused about how can I make get data from CSV to this pattern.
I have created a dummy dataset that I believe could be suitable for this task. here you can see
int year, book [title.......,author..,publishers], List<book> [[title.......,author..,publishers],[title.......,author..,publishers],.....], List<String> [panelmember1,panelmember2,panelmember3,.....panelmember(n)], String chairperson
///////////////////////////////multiple entries as above//////////////////////////////////
Tell me if I am doing right ? ... I have tried to scan this .txt file through the scanner but this wasn't helpful because I was trying to split the line through "," but can be able to get book class parameters. let me know how can I get these parameters in java.
Here is the complete question of the problem u can check
You are required to write a Java 8 program that opens and reads a
delimited data file that is located relative to the NetBeans project
root folder. The delimited data file contains information about Booker
prize winning and shortlisted novels. The data file is called
booker-data.txt. The data file must not be altered and should be
considered as a read-only data file.
The data file is delimited in a consistent structure and contains
entries relating to 20 years of Booker prize winners and shortlisted
nominees. Each entry contains a series of data fields representing the
following information: the year of the prize, the winning author, the
winning book title, the authors and book titles of shortlisted
nominees, the panel members who were responsible for deciding the
winner, and an indication of which panel member acted as chairperson.
You are required to implement Java classes to represent the Booker
prize winning information with respect to this data set. The program
should parse the data file and create and store a collection of
objects for each entity.
Figure 3 provides a partial UML class representation of the classes
that you will need to implement. It illustrates a core class to
represent the Booker prize information alongside a utility class to
represent the basic details of a book. The class model indicates the
data members and accessor (i.e., getter) methods that map to those
data members, and a toString() method for the BookerPrize class. It is
left to you to determine how the objects should be initialised. Once
all the objects are loaded into the collection, the program should
present the User with a console-based menu to interact with the data
set.
This menu should loop until the User enters a character to exit the
menu (e.g., zero as illustrated below). In addition to an exit option,
the menu should offer three other options: list, select and search. On
starting the program, the following menu should be displayed to the
console:
---------------------- Booker prize menu
---------------------- List ................1 Select ..............2 Search ..............3 Exit.................0
---------------------- Enter choice:>
The User can simply exit the program by entering zero. The three other
menu options allow the User to inspect the information in the data set
(note again that this program is entirely read-only and there is no
requirement to add, update or delete any part of the data set). The
necessary interaction of the program with respect to these options is
illustrated in Appendix A.
Note that console output should be neatly formatted, and some
consideration will be given to formatting when the program is
assessed. In particular, when the option to view the details of the
Booker prize winner and shortlist for a given year is selected (i.e.,
the ‘select’ menu option), it must result in the invocation of the
toString() method for that particular BookerPrize object. You are
required to utilise a StringBuilder object when implementing the
toString() method for the BookerPrize class.
It sounds like you're looking for an algorithm to (1) parse CSV files and (2) convert text to a Java objects.
For (1) you can use a CSV parsing library like opencsv, check out this guide: https://mkyong.com/java/how-to-read-and-parse-csv-file-in-java/ . For (2) you can use a deserialization library like jackson, check out this guide: https://www.baeldung.com/jackson-deserialization.
When you use a java.io.Scanner to read file contents the library is reading each line and converting it into a String object (string of text). So, if you want to solve (2) yourself, you will need to first define a format on how you want to write each structure (e.g., arrays) and then create an algorithm to convert it into a Java structure (e.g., java.util.ArrayList). For example, let's say you define the format for arrays to be delimited by | (e.g., a|b|c), then you can write a function to convert this to a list and use this function as part of your program.
List toList(String csvColumnStr) {
return Arrays.asList(csvColumnStr.split('|'))
}
CSV is intended for flat tabular data.
You want more.
In a quoted field you could have again comma separated text, which you could parse in a second step. A List<string> for instance.
For a List<Book> (please capitalize class names) there exists an other technique:
using different record types, placing in an additional first field the record type:
BookerPrize ... ... ...
Book ... ...
Book ... ...
BookerPrize ... ... ...
Book ... ...
Book ... ...
However all this is very circumstantial.
Some probably would advise to use the hierarchical JSON format.
I am more the friend of XML, which has a validated syntax, so dangerous typos are easily found, and you can use java with Jakarta XML Binding (formerly JAXB, Java Architecture for XML Binding) annotations to read and write Java objects. Quite easy. Also the types do not need hand-made conversion.

How to read data from a .txt file into an ArrayList to create objects

I have designed a program that reads information(customers and courses) off of two text file documents and place them into their respective ArrayList.
For example course data looks like this:
output.format("%s;%s;%s;%.2f;%s;%s;%s;%s;%b;%d;%s\r\n","Online","Java1","Davis",125.00," 1/1/2015"," 2/1/2015"," programming"," UTA ", true,12," Jones");
Notice the name of the customer "Jones" is placed at the end of the string of data so that I know which course goes to which customer.
And customer data looks like this:
output.format("%s;%d;%s;%s;%s;%d;%d;%s\r\n","Jones",786,"Cooper","Arlington","Texas",76019,12345,"student");
Notice that the customerType is placed at the end the string of data.
The first file is called customers.txt and I use a readCustomers method, located in my test case, which reads the customers.txt file, creates customers using the data, and adds them to an ArrayList called customerList.
ArrayList<Customer> customerList = new ArrayList<Customer>();
The second file is called courses.txt and I use a readCourses method, also located in my test case) which reads the the file, creates courses using the data, and finally adds the courses to their respective/correct customer. I utilize a second ArrayList called courseList to achieve this.
ArrayList<Course> courseList = new ArrayList<Course>();
I have 7 other classes in this program: Date,Time,Customer,Course,OnLineCourse,InClassCourse,Invoice(interface).
After customers are loaded with their respective customer, a method called generateInvoice calls method createInvoice in class customer which calculates the invoice for each customer and finally printing it out to a dialog box under the headings Name, Account, and Total
My problem is that I do not know how to create new customers from the customers.txt file and add them to customerList
My attempt at readCustomers method looks like this:
public static void readCustomers()
{
Scanner input;
String sentence;
String values[];
try
{
input = new Scanner(new File("customer.txt"));
while(input.hasNext())
{
sentence = input.nextLine();
values = sentence.split(";");
for(Customer c:customerList)
{
if((c.getName().equals(values[9])))
{
customerList.add(new Customer(values[0],createAddress(values[1]),Integer.parseInt(values[2])));
}
}
}
}
// there is a catch block in my program
First of all, you have to make sure the "customer.txt" file is in the right place, if you have a FileNotFoundException...
Then several things in the code above:
When I read the example of customer line, I count 11 properties. I'm wondering what you test in if((c.getName().equals(values[9]))); it doesn't look like the name of the customer.
You are reading in a list customerList which - guessing here - contains the list of Customer with only the name set, and you want to create a list of Customer beans with the additional information found in the file.
If this is the intention,
either you need to create another list and add a new instance of Customer initialised with the properties read from the file. The function readCustomers() should return the new List<Customer>.
or you want to update the Customer bean instances that are in the customerList. But in this case, you have nothing to add to the list. You just need to get each bean instance, set the properties, and continue. At the end of the function, the customerList shall be updated.

Accessing variable of ArrayList inside class

The class Task is describing tasks for a business which includes the variables: date, description, total amount of hours the task will take to complete, and the owner of the task.
An ArrayList is created for all the tasks named tasks. The problem is that a task can have more than one owner, meaning that creating a variable called owner wont work, so what I've done is that I created another class called TaskOwner and implemented that class as an ArrayList named taskOwner inside the Task class.
Now to the problem: You are supposed to be able to list tasks by a specific owner: meaning that you need to compare owners to the name you enter on your keyboard.
The problem in this lies within these lines of code:
System.out.println("What name of owner do you want to list tasks for: ");
String nameOfOwner = keyboard.nextLine();
if (nameOfOwner.toLowerCase().equals(tasks.get(1).getTaskOwner().getName().toLowerCase())) {
System.out.println(tasks.get(1));
}
I can't seem to access the variable named name inside the class TaskOwner, even though I've created getters for everything that is needed, so does anyone know how I am supposed to be able to access this information?
The error message I get is:
The method getName() is undefined for the type ArrayList
getTaskOwner appears to return an object of type ArrayList and not TaskOwner (that's what the error message indicates). In other words, it returns a list of owners. To call the getName() method, you need to loop over this list, and call the method on each element corresponding to an instance of TaskOwner.
System.out.println("What name of owner do you want to list tasks for: ");
String nameOfOwner = keyboard.nextLine();
for(int i = 0; i < tasks.size(); i++) {
List<TaskOwner> owners = tasks.get(i).getTaskOwner();
for(TaskOwner owner : owners) {
if (nameOfOwner.toLowerCase().equals(owner.getName().toLowerCase())) {
System.out.println(tasks.get(i));
break;
}
}
}
This returns an ArrayList:
tasks.get(1).getTaskOwner();
So you will need to call array list methods on it such as contains(...)
if (tasks.get(1).getTaskOwner().contains(nameOfOwner.toLowerCase())) {
As pointed out in other answers, the problem is you are calling getName() on an ArrayList<> instead of an object inside the ArrayList. The correct way of doing this would be to loop over all the tasks and then for each task, loop over their owners. Here is a sample piece of code, assuming the owners name is stored in the variable nameOfOwner:
for(Task task: tasks) {
for(TaskOwner owner: tasks.getTaskOwner) {
if (nameOfOwner.toLowerCase().equals(owner.getName().toLowerCase())) {
System.out.println(task);
break;
}
}
}
If you have also overloaded the equals method in the class TaskOwner to do a string match for the owner's name, you could just use the Arraylist.contains() method. But then, you will need to create a TaskOwner object out of the user input.
If your intention is to do task and owner lookups, you should also consider using HashMap. This would give you a better performance than ArrayList<> for direct lookups.

How to merge an array of objects into a single formatted String

I have been looking for this answer for the past 2 hours with no luck so I am posting my question now. I am sorry if it is similar to one already asked but I could not get an clear answer from what was already answered.
Here goes:
I am doing a school project in which we read in a text file of "Computer" objects (there are 8 fields in total in this form: manufacturer:model:memory:diskMemory:CPU:opticalDrive:OSVersion:RetailPrice)
once the file is read you are supposed to separate the fields and construct an array of Computer objects using the constructor that accepts all the above parameters (separated) and store their reference in each position of the array.
Here is where my question is:
Afterwards you display a menu and the user selects a few option, the simplest is just to display the list of computer object in the following form on a JOPtionPane:
Manufacturer1 model1 memory1 disk1 CPU1 optical1 OS1 retailPrice1
Manufacturer2 model2 memory2 disk2 CPU2 optical2 OS2 retailPrice2
and so on until you finish the array. I cannot figure out how to condense the array of objects into a single string that is in the form above. The Computer class has a getMethod for each of those fields I am just having trouble getting them to be aligned in that way. It has to be on a JOPtionPane the simple .INFORMATION_MESSAGE kind. If you all need to see the Computer class code let me know and I can post it. This is my first time posting on this website so I apologize if it is in improper form.
Thank you so much for your help,
Bob
EDIT:
This is what the output should look like:
http://i229.photobucket.com/albums/ee38/Yukijin-Uchiha/ScreenShot2014-03-14at113759AM_zps05b5dbb5.png
If you implement the Computer classes toString() function properly, you should get just what you want. For example:
public class Computer {
public String toString() {
return (new StringBuilder(getManufacturer()).append(":").
append(getModel()).append(":").
append(getMemory()).append(":").
append(getDiskMemory()).append(":").
append(getCPU()).append(":").
append(getOpticalDrive()).append(":").
append(getOSVersion()).append(":").
append(getRetailPrice()).
toString();
}
}
Then call it with
String computerObjAsString = aComputerInstance.toString();
To do this with an array of Computer objects:
StringBuilder outBldr = new StringBuilder();
for(Computer cmptr : anArrayOfComputers) {
outBldr.append(cmptr).append(System.getPropetry("line.separator", "\r\n"));
}
System.out.println(outBldr);
You should look to override the toString() method in your Computer objects to include the details that you want printed. Then, for each Computer object in your array, call <object name>.toString() to display the appropriate information.
public class Computer {
private String name;
private String type;
public Computer(String n, String t) {
this.name = n;
this.type = t;
}
public String toString() {
return "Name: " + this.name + " Type: " + this.type;
}
public static void main(String[] args) {
Computer c = new Computer("atari","old-school");
System.out.println(c.toString());
}
}

how do I pass information from one class to another

I am creating a program which allows the user to input details of customers. When they have saved each customers record there is the choice to add additional information. I am having trouble getting the the name of the saved file in my append class. I need the filename so I can then save the additional information to the same file already created for the customer. How do I pass the file name from one file to another.
File FName = fileChooser.getSelectedFile();
String name = FName.getName();
public String getname() { return name; }
This code is in my customer class how do I get this information in my append class??
Possibly something like this:
Customer customer = new Customer();
// do some stuff with your customer object, including initiating the File and saving its name to a String field called name
Append append = new Append();
append.foo(customer.getName()); // passes the name of the file to the foo method of class Append
This assumes that you'll only want the name of the file in that one method (though you could save it to a field as part of method foo()). You'd need to implement a method foo(String name) in class Append.
Another option would be to pass it as a constructor of Append:
Append append = new Append(customer.getName());
append.foo();
For this, you'd need to implement a constructor Append(String name) in class Append.
There are a couple of ways to do this depending on what exactly it is you are trying to do.
Give the Append class a member variable of the Customer class
Have the Append class constructor take a parameter that would refer to a Customer, such as a String of name or a Customer object as this is Java
Your question is not entirely clear to me, but here's a problems you might run into based on your description:
What is getName() supposed to return, the name of the file, or the name of the person? If it's supposed to return the file name, then use getFileName() instead - it's clearer!
I don't really understand why you'd need an Append class. Personally, I'd handle appending additional info inside the Customer class. I'd do it so that every time a value is added or changed, the info is saved back into the file like:
class Customer {
public void setForename(String forename) {
this.forename = forename;
save();
}
public void setSurname(String surname) {
this.surname = surname;
save();
}
public void save() {
// clear file
// add new content
String fileContents = "forename="+forname+"&surname="+surname;
// save to file
}
Maybe I'm not understanding your needs correctly though...
In addition to DeadPassive's answer of associating the additional information with the Customer object:
The saving of the Customer data does not belong in the Customer Class. The logic of persisting the data belongs in a seperate layer than the code that deals with manipulating the problem domain. A controller or service class seems like a more appropriate place to put the persistance logic.

Categories

Resources