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.
Related
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 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;
}
I wanna make an ArrayList of Student and save it to a file for later use. I successfully wrote it but when I read it back to ArrayList, I have only one Object.
public class Student implements Serializable{
public String fname, lname, course;
int section;
private static final long serialVersionUID = 1L;
public static ArrayList<Student> students = getStudent();
public Student() {
}
public Student(String fname, String lname, String course, int section){
this.fname = fname;
this.lname = lname;
this.course = course;
this.section = section;
}
public static void addStudent(){
String fname = GetInput.getInput("Enter the First Name: ");
String lname = GetInput.getInput("Enter the Last Name: ");
String course = GetInput.getInput("Enter the Course: ");
String S_section = GetInput.getInput("Enter the section: ");
int section = Integer.parseInt(S_section);
Student student = new Student(fname, lname, course, section);
students.add(student);
System.out.println("Writing to file...");
try {
writeToFile(student);
} catch (FileNotFoundException ex) {
System.out.println(ex.getMessage());
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
public static ArrayList<Student> getStudent(){
try{
FileInputStream fis = new FileInputStream("C:\\students.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
ArrayList<Student> students1 = (ArrayList<Student>) ois.readObject();
ois.close();
return students1;
} catch( ClassNotFoundException | IOException ex){
System.out.println(ex.getMessage());
return null;
}
}
public static void listStudent(ArrayList<Student> students){
System.out.println("View the Records in the Database:");
for(Student student: students){
System.out.println("Name: " + student.fname + " " + student.lname);
System.out.println("Course: " + student.course);
System.out.println("Section: " + student.section);
System.out.println();
}
}
static void writeToFile(Student student) throws FileNotFoundException, IOException{
String path = "C:\\students.ser";
FileOutputStream fos = new FileOutputStream(path, true);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(student);
oos.close();
System.out.println("New Record has been written!");
}
When I read file by calling getStudent() and print it out by listStudent() I have only one record of the file.
Please help me!
Much appreciate.
EDIT
I had tried writing an arraylist to file and read it into arraylist. I'll show you how I did that.
Firstly, I write arraylist to file:
public static ArrayList<Student> students = new ArrayList<>();
public static void addStudent(){
Student student = new Student(fname, lname, course, section);
students.add(student);
System.out.println("Writing to file...");
try {
writeToFile(students);
}catch...
}
static void writeToFile(ArrayList<Student> students) throws FileNotFoundException, IOException{
String path = "C:\\students.ser";
FileOutputStream fos = new FileOutputStream(path, true);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(students);
oos.close();
System.out.println("New Record has been written!");
And then I read student file:
public static ArrayList<Student> getStudent(){
try{
FileInputStream fis = new FileInputStream("C:\\students.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
ArrayList<Student> students1 = (ArrayList<Student>) ois.readObject();
ois.close();
return students1;
} catch( ClassNotFoundException | IOException ex){
System.out.println(ex.getMessage());
return null;
}
}
I can see that in the file I have many objects as the file size keep growing. But I only one object after read it, which is my very first object I wrote to file.
I would suggest you update your Serialization code for your Student class (because you're not Serializing your static students) as follows -
// This controls how Student(s) will be written.
private void writeObject(ObjectOutputStream oos)
throws IOException {
oos.defaultWriteObject();
// How many students we're tracking.
oos.writeInt(students.size());
for (Student student : students) {
oos.writeObject(student);
}
System.out.println("session serialized");
}
// Control how we read in Student(s).
private void readObject(ObjectInputStream ois)
throws IOException, ClassNotFoundException {
ois.defaultReadObject();
// how many Students to read.
int size = ois.readInt();
for (int i = 0; i < size; i++) {
Student s = (Student) ois.readObject();
students.add(s);
}
System.out.println("session deserialized");
}
You state in comment:
Thanks for your comment. I noticed that, however I appended the new object to the old file, so technically I have bunch of objects in my file. FileOutputStream fos = new FileOutputStream(path, true);
While this technically does append to the end of a file, and works great with text files, I really don't think that this will work or work well with serialization. I would guess that to append with serialization, you'd first have to read all the objects in from the file, and then write without appending all of them via the serialization mechanism. I would re-write your input and output code if I were you.
Edit
I fear that you've got too much disparate stuff all crammed into one single class, making for a messy and hard to debug program. Some general recommendations to help clean up this assignment:
First create a class called Student -- you've done this -- but make it a pure Student class with private first name, last name, section and course fields, getters and setters for those fields (you need these), appropriate constructors (I think you've got this).
Give it a decent public String toString() method that returns a String that holds the values of the object's fields.
Get everything else out of Student, all the static methods, all the ArrayLists, any code for writing to or reading from files.
Create another class, say called StudentCollection
Give it a private non-static ArrayList<Student> field, say called students.
Give it an addStudent(Student student) method that allows outside classes to add Student objects to this class.
Give it a public String toString() method that returns the list's toString(), i.e., return students.toString();.
Give it a public void readFromFile(File file) method that uses serialization to read an ArrayList<Student> from a File.
Give it a public void writeToFile(File file) method that uses serialization to write an ArrayList<Student> to a File.
Finally, create a TestStudent class that has only one method, a public static void main method.
In main, create a StudentCollection object.
Fill it with Students using your addStudent(...) method.
Create a File object and call writeToFile(...) passing in your File.
Then test reading from the same file...
For example, the main method could look almost like the code below. Note though that in my test case to prove that this works, I created a simplified Student class, one that only took 2 parameters, for first and last names. Your code obviously will take more parameters.
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class StudentTest {
private static final String DATA_FILE_PATH = "myFile.dat";
public static void main(String[] args) {
Student[] students = {new Student("John", "Smith"),
new Student("Mike", "Barnes"),
new Student("Mickey", "Mouse"),
new Student("Donald", "Duck")};
// create our collection object
StudentCollection studentColl1 = new StudentCollection();
// print out that it currently is empty
System.out.println("studentColl1: " + studentColl1);
// Add Student objects to it
for (Student student : students) {
studentColl1.addStudent(student);
}
// show that it is now full
System.out.println("studentColl1: " + studentColl1);
// create a file
File myFile = new File(DATA_FILE_PATH);
// write out our collection to file on disk
studentColl1.writeToFile(myFile);
// create another collection object
StudentCollection studentColl2 = new StudentCollection();
// show that it is empty
System.out.println("studentColl2: " + studentColl2);
// read the list back into the new StudentCollection object
File myFile2 = new File(DATA_FILE_PATH);
studentColl2.readFromFile(myFile2);
// add a few more Student's:
studentColl2.addStudent(new Student("Stack", "Overflow"));
studentColl2.addStudent(new Student("Donald", "Trump"));
// show the result
System.out.println("studentColl2: " + studentColl2);
}
}
You're writing a single Student object:
oos.writeObject(student);
But are trying to get an ArrayList:
ArrayList<Student> students1 = (ArrayList<Student>) ois.readObject();
so i can't figure out how to print an arraylist index (the first index so 0) to a text file. Basically, I have a Job class which stores 5 variables
public class Job {
public int teamNo;
public String regNo;
public String gridRef;
public String gridCopy;
public String toString() {
return "Job [teamNo=" + teamNo + ", regNo=" + regNo + ", gridRef="
+ gridRef + "";
}
and then I have an arraylist of type Job:
private static ArrayList<Job> teamNoOne = new ArrayList<Job>();
So the data all gets added fine, prints it out etc but I can't save it to a text file. this is my code, I just get the random hash code of it but I need it in human readable form.
try {
File file = new File("JOBS-DONE-LOG.txt");
FileOutputStream fs = new FileOutputStream(file);
ObjectOutputStream os = new ObjectOutputStream(fs);
System.out.println(teamNoOne.get(0));
os.writeObject(teamNoOne.get(0));
os.close();
} catch (IOException e1) {
e1.printStackTrace();
}
Can't figure out how to do it.
writeObject serializes the object in your file, it doesn't write it in textual form (http://docs.oracle.com/javase/7/docs/api/java/io/ObjectOutputStream.html#writeObject(java.lang.Object))
You must do it in another way: for example, you can use the BufferedWriter class and the write method to write the output of your toString() method.
Here is a complete example:
import java.io.File;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.util.ArrayList;
public class Job {
public String regNo;
public String gridRef;
public String gridCopy;
public String toString() {
return "Job [teamNo=" + teamNo + ", regNo=" + regNo + ", gridRef="
+ gridRef + "";
}
public static void main(String[] args) throws Exception {
ArrayList<Job> teamNoOne = new ArrayList<Job>();
// fill your array
Job job = new Job();
job.regNo = "123";
// continue to fill the jobs...
teamNoOne.add(job);
BufferedWriter writer = new BufferedWriter(new FileWriter("JOBS-DONE-LOG.txt"));
System.out.println(teamNoOne.get(0));
writer.write(teamNoOne.get(0).toString());
os.close();
}
}
Since you are trying to save an arraylist of type Job, it has to be serialized (Refer this).
public class Job implements java.io.Serializable
{
public int teamNo=0;
public String regNo="default";
public String gridRef="default";
public String gridCopy="default";
public String toString() {
return "Job [teamNo=" + teamNo + ", regNo=" + regNo + ", gridRef="
+ gridRef + "";
}
}
For Saving the file
try
{
FileOutputStream fileOut = new FileOutputStream(path);
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(teamNoOne);
out.close();
fileOut.close();
}
catch(IOException i)
{
i.printStackTrace();
}
Thus you can load the arraylist back like
Object o = null;
try
{
FileInputStream fileIn = new FileInputStream(path);
ObjectInputStream in = new ObjectInputStream(fileIn);
o = in.readObject();
in.close();
fileIn.close();
}
catch(IOException i)
{
i.printStackTrace();
}
catch(ClassNotFoundException c)
{
c.printStackTrace();
}
Arraylist<Job> loaded_Job = (ArrayList<Job>) o;
Then print the arraylist
for(int i = 0; i < loaded_Job.size(); i++) {
loaded_Job.get(i).toString();
}
This happens because you didn't parameterize your ArrayList. Use generics when declaring your list:
ArrayList<Job> teamNoOne = new ArrayList<Job>();
Because now, though you have overriden your toString() method, teamNoOne.get(0) uses an Object's toString().
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.