I have written a java program that needs to save a list of an Object I created called User. This is my code for saving and loading the list:
/**
* Save list to file
* #param saveList list to be saved
*/
public void saveUsers(List<User> saveList){
try{
FileOutputStream fileOut = new FileOutputStream("data/userlist.ser", true);
OutputStream out = new BufferedOutputStream(fileOut);
ObjectOutput output = new ObjectOutputStream(out);
output.writeObject(saveList);;
out.close();
fileOut.close();
output.close();
for(User u : saveList){
System.out.println(u.getUsername());
}
System.out.println("List written to file");
}catch(IOException e){
e.printStackTrace();
}
}
/**
*
* #return list of all users in system.
*/
#SuppressWarnings({ "resource", "unchecked" })
public static List<User> loadUsers(){
try{
InputStream saveFile = new FileInputStream("data/userlist.ser");
InputStream buffer = new BufferedInputStream(saveFile);
ObjectInput input= new ObjectInputStream(buffer);
LinkedList<User> loadList = (LinkedList<User>) input.readObject();
System.out.println(loadList.size());
for(User u : loadList){
u.reload();
System.out.println(u.getUsername());
}
return loadList;
}catch(Exception e){
e.printStackTrace();
}
List<User> l = new LinkedList<User>();
return l;
}
And my code seems to work for save because the output each time it is called shows all the users being added to the list, however on the load it only loads the first User. This is my user class:
public class User implements Serializable{
/**
* Variables
*/
private transient StringProperty usernameProperty;
private String username;
private List<Album> albums = new LinkedList<Album>();
private List<Photo> photos = new LinkedList<Photo>();;
private List<Tag> tags = new LinkedList<Tag>();;
private static final long serialVersionUID = 1738L;
/**
* public constructor to create a user
* #param username
*/
public User(String username){
this.username = username;
this.usernameProperty = new SimpleStringProperty(username);
}
And all of my other classes are implementing the Serializable as well. Is there any reason the list is being saved to the file but not loading fully?
I figured out the answer, apparently every time I was calling the save class, I was not overwritting the file but appending to it, so I was only reading the first array list being stored, pretty simple fix I just added the lines
File file = new File("data/userlist.ser");
file.delete();
to the beginning of my saveUsers function to clear the file, now it works perfectly.
Change LinkedList loadList = (LinkedList) input.readObject(); to ArrayList. Edit the file userlist.ser delete the contents or create a new file and use it in your code. It works fine for me.
Finding the error in your code is for me more complex than testing my own solution, so I have made a quick model for you, using a the same classes you use, but using a custom class (car) for this...
the Code:
public static void main(String[] args) throws Exception {
final Car c0 = new Car("bmw", 1990);
final Car c1 = new Car("VW", 2000);
final Car c2 = new Car("Audi", 2010);
final Car c3 = new Car("Mini", 2015);
final LinkedList<Car> lisCar = new LinkedList<Car>();
lisCar.add(c0);
lisCar.add(c1);
lisCar.add(c2);
lisCar.add(c3);
serialThis(lisCar);
deserializeFileToList();
}
Serialize to file:
private static void serialThis(LinkedList<Car> lisCar) throws Exception {
final FileOutputStream fos = new FileOutputStream("serialized.txt");
final ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(lisCar);
oos.close();
}
Deserialize from file:
private static void deserializeFileToList() throws Exception {
final FileInputStream fis = new FileInputStream("serialized.txt");
final ObjectInputStream ois = new ObjectInputStream(fis);
final LinkedList<Car> ds = (LinkedList<Car>) ois.readObject();
ois.close();
System.out.println(ds);
}
The Car class:
private static final long serialVersionUID = -427928246789764110L;
#Override
public String toString() {
return "Car [year=" + year + ", type=" + type + "]";
}
private final int year;
private final String type;
public Car(String type, int year) {
this.type = type;
this.year = year;
}
Related
I am working on a school project that basically allows the user to create, edit and display students. I have a createStudent() that writes the info into the file using Scanner and ObjectOutputStream. The displayStudent() reads the data from the file using ObjectInputStream and displays it. The idea with editStudent() is to ask the user to enter the ID of the student they want to edit and then change the date and write it back to the file, what I have been trying to do is read the data from the file using ObjectInputStream and then assign that data into ArrayList or HashMap, I think I will be using ArrayList because HashMap is unordered. When I try to add the data from the file into ArrayList I get the following error:
java.io.EOFException at java.base/java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:3231) at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1663) at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:519) at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:477) at MidTermProject.editStudent(MidTermProject.java:194) at MidTermProject.main(MidTermProject.java:381)
Here is my code for editStudent():
public static void editStudent() throws IOException {
int editID;
String student;
ArrayList<String> studentEdit = new ArrayList<String>();
Scanner keyboard = new Scanner(System.in);
FileInputStream fstream = new FileInputStream("studentInfo.dat");
ObjectInputStream inputFile = new ObjectInputStream(fstream);
System.out.print("Enter the ID of the student you would like to edit: ");
editID = keyboard.nextInt();
try {
student = (String) inputFile.readObject();
studentEdit.add(student);
System.out.print(studentEdit);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
///Added create student method
public static void createStudent() throws IOException {
File file = new File("studentInfo.dat");
boolean append = file.exists();
Scanner keyboard = new Scanner(System.in);
try (
FileOutputStream fout = new FileOutputStream(file, append);
MidTermProject oout = new MidTermProject(fout, append);
) {
id = idGenerator.getAndIncrement();
String convertedId = Integer.toString(getId());
oout.writeObject(convertedId);
System.out.print("\nPlease enter your information bellow.\n" + "\nFull Name: ");
FullName = keyboard.nextLine();
oout.writeObject(FullName);
System.out.print("Address: ");
address = keyboard.nextLine();
oout.writeObject(address);
System.out.print("City: ");
city = keyboard.nextLine();
oout.writeObject(city);
System.out.print("State: ");
state = keyboard.nextLine();
oout.writeObject(state);
oout.close();
System.out.println("Done!\n");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Here is the class code for MidTermProject
public class MidTermProject extends ObjectOutputStream {
private boolean append;
private boolean initialized;
private DataOutputStream dout;
static AtomicInteger idGenerator = new AtomicInteger(0001);
static int id;
public static String FullName;
public static String address;
public static String city;
public static String state;
public static String className;
public static String instructor;
public static String department;
public static String classNumber;
public static String courseNumber;
public static String year;
public static String semester;
public static String grade;
public static String studentID;
public static String courseID;
public static String enrollmentID;
public static HashMap<String, Integer> map = new HashMap<>();
Scanner keyboard = new Scanner(System.in);
protected MidTermProject(boolean append) throws IOException, SecurityException {
super();
this.append = append;
this.initialized = true;
}
public MidTermProject(OutputStream out, boolean append) throws IOException {
super(out);
this.append = append;
this.initialized = true;
this.dout = new DataOutputStream(out);
this.writeStreamHeader();
}
#Override
protected void writeStreamHeader() throws IOException {
if (!this.initialized || this.append) return;
if (dout != null) {
dout.writeShort(STREAM_MAGIC);
dout.writeShort(STREAM_VERSION);
}
}
If think you are misusing serialization: whether Serialization is bad or good is another matter, but that should be something like that:
List<Student> students = ... ;
try (OuputStream os = Files.newOutputStream(Paths.get("out"));
ObjectOutputStream oos = new ObjectOutputStream(os)) {
oos.writeObject(students);
}
Reading it should be as simple as:
try (InputStream is = Files.newInputStream(Paths.get("out"));
ObjectInputStream iis = new ObjectInputStream(is)) {
List<Student> students = iis.readObject(students);
}
You must ensure that Student is Serializable and have only Serializable or transient fields:
class Student implements Serializable {
private static final long serialVersionUID = 1L;
private long id;
private String fullName;
private String address;
private transient String wontBeExported;
...
}
Notice that the fields are not static: serialization is about serializing an object and its fields. Static fields are not part of any instance.
You should also not have to extends the ObjectOutputStream class, or if you do, you must ensure that you read the object written by your implementation of ObjectOutputStream is symmetric with the ObjectInputStream you are using:
If you write an header, your ObjectInputStream must read said header.
If you write an object, your ObjectInputStream must read said object.
And the order is important: you can't read the object before the header is read.
You should also read the Java tutorial: https://docs.oracle.com/javase/tutorial/jndi/objects/serial.html
I need to store and read ArrayList Objects to a file, which that itself isn't the issue. I need to store it with a specific format and have it have a "header" of sorts while still having each ArrayList Object be usable from the file. Another part to it, is it needs to be readable by opening the text file itself, so no serialization can be used (Unless I'm just severely mistaken on how to use serialization). Example of how the working file should look below (Figure 1).
I will include all my code below just so nothing important isn't show on accident.
Airline.java
public class Airline extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("Airline.fxml"));
Scene scene = new Scene(root);
stage.setTitle("Seat Reservation");
stage.setResizable(false);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
Passenger p1 = new Passenger(0001, "John Smith", "1A", "AA12");
Passenger p2 = new Passenger(0002, "Annah Smith", "1B", "AA12");
//creating arraylist
ArrayList <Passenger> pList = new ArrayList <Passenger>();
pList.add(p1);
pList.add(p2);
try {
FileOutputStream fos = new FileOutputStream(new
File("reservations.txt"));
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(pList);
oos.close();
fos.close();
FileInputStream fis = new FileInputStream(new
File("reservations.txt"));
ObjectInputStream ois = new ObjectInputStream(fis);
ArrayList list = (ArrayList) ois.readObject();
System.out.println(list.toString());
ois.close();
fis.close();
} catch (FileNotFoundException e) {
System.out.println("File not found");
} catch (IOException e) {
System.out.println("Error initializing stream");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
launch(args);
}
}
Passenger.java
public class Passenger implements Serializable {
private static final long serialVersionUID = 1L;
private int id;
private String name;
private String seat;
private String flight;
Passenger() {
};
public Passenger (int idP, String nameP,String seatP, String flightP) {
this.id = idP;
this.name = nameP;
this.seat = seatP;
this.flight = flightP;
}
#Override
public String toString() {
return "\n" + id + " " + name + " " + seat + " " + flight;
}
}
The code I have currently shows this when opening the text file (Figure 2 below).
If anyone has any suggestions please let me know! I've been stumped for quite a while now.
Also, if this breaks any rules or doesn't have the proper tags, let me know and I'll remove/edit it.
In your example you use serialization (you can read more about it here Introduction to Java Serialization), which saves an object to a file in binary format. So basically you're saving the whole ArrayList, including its internal fields and values as an array of bytes.
But what you really need is simply writing to a text file.
Here's one of the ways you can do that using java.io.PrintWriter:
PrintWriter p = new PrintWriter("reservations.txt");
p.write("your text goes here");
And yes, you have to prepare the text for writing manually.
In your case the best approach would be overriding toString() method of Passenger class, so you can write to a file as simply as this:
Passenger p1 = new Passenger(0001, "John Smith", "1A", "AA12");
Passenger p2 = new Passenger(0002, "Annah Smith", "1B", "AA12");
p.write(p1.toString());
p.write(p2.toString());
toString() method has to concatenate required fields(ID, Name, SeatNumber, Flight#) and return them as a single String with a TAB character as a delimiter.
I have a 'Person' class where i stored data like name, surname etc. I make 5 object type Person, add them to ArrayList, and save this ArrayList to file. Next i'm loading from this file ArrayList and i have 5 person. Problem is when i want save again for example 10 object Person. When i'm loading ArrayList from file i'm getting only 5 person from first writing. If i repeat this still i will have load data from first writing to this file. How i can fix this ?
public class Data {
static List<Person> persons = new ArrayList<Person>();
public static void main(String[] args) throws IOException {
Data.savePersons(5);
Data.loadPersons();
/** Clean 'persons' array for TEST of load data */
persons.removeAll(persons);
System.out.println("\n-----------\nNext Round\n-----------\n");
Data.savePersons(10);
Data.loadPersons();
}
/** Save a couple of Person Object to file C:/data.ser */
public static void savePersons(int noOfPersonToSave) throws IOException {
FileOutputStream fout = null;
ObjectOutputStream oos = null;
/** Make 5 'Person' object and add them to ArrayList 'persons' for example */
for (int i = 0; i < noOfPersonToSave; i++) {
Person personTest = new Person("name" + i, "surname" + i, "email" +i, "1234567890" +i);
persons.add(personTest);
}
try {
fout = new FileOutputStream("C:\\data.ser", true);
oos = new ObjectOutputStream(fout);
oos.writeObject(persons);
System.out.println("Saving '" + persons.size() + "' Object to Array");
System.out.println("persons.size() = " + persons.size());
System.out.println("savePersons() = OK");
} catch (Exception ex) {
System.out.println("Saving ERROR: " + ex.getMessage());
} finally {
if (oos != null) {
oos.close();
}
}
}
/** Load previously saved a couple of Person Object in file C:/data.ser */
public static void loadPersons() throws IOException {
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
fis = new FileInputStream("C:\\data.ser");
ois = new ObjectInputStream(fis);
persons = (List<Person>) ois.readObject();
//persons.add(result);
System.out.println("-------------------------");
System.out.println("Loading '" + persons.size() + "' Object from Array");
System.out.println("persons.size() = " + persons.size());
System.out.println("loadPersons() = OK");
} catch (Exception e) {
System.out.println("-------------------------");
System.out.println("Loading ERROR: " + e.getMessage());
} finally {
if (ois != null) {
ois.close();
}
}
}}
class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private String surname;
private String mail;
private String telephone;
public Person(String n, String s, String m, String t) {
name = n;
surname = s;
mail = m;
telephone = t;
}
public String getName() {
return name;
}
public String getSurname() {
return surname;
}
public String getMail() {
return mail;
}
public String getTelephone() {
return telephone;
}}
new FileOutputStream("C:\\data.ser", true)
You're passing true for the append parameter. So you're appending a list of 10 persons to the file, after the already existing list of 5 people. And since you only read one list, you read the first you wrote, which contains 5 persons.
Pass false instead of true.
I have succeeded in writing and reading a string to a file on my android app's internal storage, but I want to write an object and it's not working. I've read Oracle's documentation on the matter, which says for object fields to be transmitted over the stream the object needs to implement serializable, or something. I added imports serializable and implements serializable to the cat class but it threw an error. Without it "oos.writeObject(myCat);" causes an error too. I'm very confused.
The below code exists in a java activity class tied to a layout.xml. The user presses a button and the object is saved or loaded. As stated writing and reading a string seems to work fine, but objects less so.
private void writeFile()
{
try
{
String myFile = "myFile";
cat myCat = new cat("Harry", "blue", 11);
FileOutputStream fos = openFileOutput(myFile,MODE_WORLD_READABLE);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(myCat);
oos.close();
fos.close();
Toast.makeText(getBaseContext(),"object saved",Toast.LENGTH_SHORT).show();
}
catch (Exception e)
{
e.printStackTrace();
}
}
And
private void readFile()
{
try
{
String myFile = "myFile";
FileInputStream fis = openFileInput(myFile);
ObjectInputStream ois = new ObjectInputStream(fis);
cat yourCat = (cat) ois.readObject();
ois.close();
fis.close();
String output = yourCat.name + " the " + yourCat.colour + " cat";
Toast.makeText(getBaseContext(),output,Toast.LENGTH_SHORT).show();
}
catch (Exception e)
{
}
}
The cat object
public class cat
{
public String name = "";
public String colour = "black";
public int age = 0;
public cat(String pName, String pColour, int pAge)
{
name = pName;
colour = pColour;
age = pAge;
}
}
Adding "implements Serializable" to the cat class works. I'm not sure why it didn't in the first place. Sorry for the fuss.
Try using:
MODE_PRIVATE
In the openFileOutput() method.
I have this arrayList in my UserArchive class, and a saveFile() method in my MainWindow class.
My problem is that every time I close the program all that shows in src/customerlist.txt is:
¨ÌsrUserArchiveYï≈ùÅ—ÀDLlisttLjava/util/ArrayList;xpsrjava.util.ArrayListxÅ“ô«aùIsizexpw
x.
Heres my code: Can anyone spot any problems?
public class UserArchive implements Serializable {
ArrayList<User> list = new ArrayList<User>();
public void regCustomer(User u) {
list.add(u);
}
public String toString() {
sorter();
String users = "";
Iterator<User> iterator = list.iterator();
while (iterator.hasNext()) {
users += iterator.next().toString() + "\n";
}
return users;
}
MainWindow class:
public class MainWindow extends JFrame {
private SaleWindow sW;
private UserArchive userA;
int customerID = 0;
////
public void saveFile() {
try {
FileOutputStream outStream = new FileOutputStream(
"src/customerlist.txt");
ObjectOutputStream utfil = new ObjectOutputStream(outStream);
utfil.writeObject(userA);
utfil.close();
} catch (NotSerializableException nse) {
JOptionPane
.showMessageDialog(this, "Objektet er ikke serialisert!");
} catch (IOException ioe) {
JOptionPane
.showMessageDialog(this, "Problem med utskrift til fil!");
}
}
Yes because ObjectOutputStream serializes objects in binary form. If you want serialize in some ASCII form try a JSON Serializer for example Jackson.
Please take a look at Javas serialization mechanismn. You're not writing the String content but the String objects (and the sourrounding list) in their binary form.
ObjectOutputStream is the wrong choice if all you want to do is write a plain text file. Take a closer look at java.io.FileWriter or java.io.PrintWriter.