Serializing a list of objects - java

I am confused on how to serialize and deserialize a list of question objects.
I have a Survey class that has an attribute called Questions, which is a list of Question objects.
I want to be able to serialize the Survey properties, along with all the properties of each question.
Unfortunately I have had no luck so far, here is what I have. Thanks for the help!
public void loadData(Boolean isSurvey) throws FileNotFoundException {
System.out.println("Select a file: ");
FileInputStream fileIn;
if (isSurvey) {
String fileName = listFiles("surveys").get(input.getIntInput(fileCount - 1));
fileIn = new FileInputStream("surveys/" + fileName);
} else {
String fileName = listFiles("tests").get(input.getIntInput(fileCount - 1));
fileIn = new FileInputStream("tests/" + fileName);
}
Question q = null;
try
{
ObjectInputStream in = new ObjectInputStream(fileIn);
q = (Question) in.readObject();
in.close();
fileIn.close();
}catch(IOException i){
i.printStackTrace();
}catch(ClassNotFoundException c) {
System.out.println("Not found");
c.printStackTrace();
}
System.out.println("Deserialized Question...");
System.out.println("prompt: " + q.prompt);
}
public void saveData(Survey survey, Test test, Boolean isSurvey, String fileName) {
try {
File surveyDir = new File("surveys");
File testDir = new File("tests");
if ((!(surveyDir.exists()) && isSurvey)) {
System.out.println("Creating Survey directory. . .");
surveyDir.mkdir();
}
if ((!(testDir.exists())) && !(isSurvey)) {
System.out.println("Creating Test directory. . .");
testDir.mkdir();
}
if (isSurvey) {
FileOutputStream fileOut = new FileOutputStream("surveys/" + fileName);
ObjectOutputStream out = new ObjectOutputStream(fileOut);
for (Question question : survey.questions) {
out.writeObject(survey.questions);
}
out.close();
fileOut.close();
} else {
FileOutputStream fileOut = new FileOutputStream("tests/" + fileName);
ObjectOutputStream out = new ObjectOutputStream(fileOut);
for (Question question : test.questions) {
out.writeObject(question);
}
out.close();
fileOut.close();
}
} catch(IOException i) {
i.printStackTrace();
}
}

Have you already implemented your object to write with the java.io.Serializable
import java.io.Serializable;
public class Question implements Serializable {
//Other codes here
}
Another thing I noticed is that you have written a collection object.
for (Question question : survey.questions) {
out.writeObject(survey.questions);
}
But you are reading it as Question object.
q = (Question) in.readObject();
If the object you wrote is a Collection. Here is an example if it is List collection
q = (List<Question>) in.readObject();

Related

Java read a file into an arraylist of objects and return that arraylist

I need to write a class that has two static methods: writeFile and readFile. However, after I do my readFile(), it returns nothing.
class writereadFile {
public static void writeFile(ArrayList<Object> list, File file){
try {
try (FileOutputStream fos = new FileOutputStream(file);ObjectOutputStream oos = new ObjectOutputStream(fos)) {
oos.writeObject(list);
oos.close();
}
}catch(IOException e){e.getMessage();}
}
public static ArrayList<Object> readFile(ArrayList<Object>list, File file){
try {
try (FileInputStream fis = new FileInputStream(file);ObjectInputStream ois = new ObjectInputStream(fis)) {
Object o = ois.readObject();
list = (ArrayList<Object>) o;
ois.close();
}
}catch(IOException | ClassNotFoundException e){e.getMessage();}
System.out.println(list);
return list;
}
}
EDIT:
This my class for testing. My object is an arraylist of custom objects if you need the custom object just comment.
class main {
public static void main(String[] args) {
Date date = new Date();
Book b1 = new Book("abc", "Phi", true, date, null);
Book b2 = new Book("cba", "Someone", true, date, null);
Books booklist = new Books();
booklist.add(b1);
booklist.add(b2);
File filetoDo = new File("book.txt");
//write arraylist into file
writereadFile.writeFile(booklist, filetoDo);
//clear the arraylist
booklist.clear();
//read book from file
writereadFile.readFile(booklist, filetoDo);
System.out.println(booklist);
}
}
Your test should read:
bookList = writereadFile.readFile(booklist, filetoDo);
and, by the way, you should really refactor your readFile method to simply:
public static ArrayList<Object> readFile(File file)
You can't modify the argument reference like that, since Java is always pass-by-value call semantics. (You could modify the list argument contents inside the function, but that's not what you are doing.)
If you are using Java 8 try using Streams:
public static readFile(String filePath) {
List<Object> list = new ArrayList<>();
try (Stream<String> stream = Files.lines(Paths.get(filePath))) {
stream.forEach(list::add);
} catch (IOException e) {
e.printStackTrace();
}
return list;
}
I'm playing around this topic a bit on my own, so below you can find some code snippets that might help you.
Examples are very short and simple, so I hope you will not just use e.printStackTrace() in your code :)
public class ExternalIO {
private ExternalIO() {
}
public static ObjectOutputStream objectOutputStream(String basePath, String pathToFile) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream(createFileIfDoesNotExist(absolutePath(basePath, pathToFile)));
return new ObjectOutputStream(fileOutputStream);
}
public static ObjectInputStream objectInputStream(String basePath, String pathToFile) throws IOException {
FileInputStream fileInputStream = new FileInputStream(absolutePath(basePath, pathToFile));
return new ObjectInputStream(fileInputStream);
}
private static File createFileIfDoesNotExist(String absolutePath) throws IOException {
File file = new File(absolutePath);
if (file.exists()) {
return file;
}
file.getParentFile().mkdirs();
file.createNewFile();
return file;
}
private static String absolutePath(String basePath, String pathToFile) {
return Paths.get(basePath, pathToFile).toAbsolutePath().toString();
}
}
output usage:
List<ItemType> input = null; //create your input list here
try (ObjectOutputStream objectOutputStream = ExternalIO.objectOutputStream(CONFIG, FILENAME)) {
objectOutputStream.writeObject(input);
} catch (Exception e) {
e.printStackTrace();
}
input usage:
try (ObjectInputStream objectInputStream = ExternalIO.objectInputStream(CONFIG, FILENAME)) {
return (List<ItemType>) objectInputStream.readObject();
} catch (Exception e) {
e.printStackTrace();
}
hope that helps ; )

Java Streams read files and print objects read on files

So guys i need some help. I have a class Book and i want to save my books object to a Stream and then read this Stream file so i can search my objects from there. I have written my code but it gives me some errors and i can figure out how to print my books values .
So this is my Book class
public class Book {
private Date arr;
private Date depp;
private Type room;
private boolean breakfast = false;
private Person data;
private ObjectOutputStream out;
public Book(String name, String surename, String phone,Date arr, Date depp, Type room, boolean breakfast) {
data = new Person(name,surename,phone);
this.arr = arr;
this.depp = depp;
this.room = room;
this.breakfast = breakfast;
}
public void writeObjToFile(){//here i save my object to stream it gives me error, i call this method after i create my book object to main
try{
out = new ObjectOutputStream(new FileOutputStream("books.txt"));
out.writeObject(this);
}
catch(FileNotFoundException e){
System.err.println("File not Found");
e.printStackTrace();
}catch(IOException e){
System.err.println("IOException");
e.printStackTrace();}
}
}
and this is my Search class :
public class Search {
private FileInputStream fis=null;
private String filename;
public Search(String filename){
this.filename = filename;
File file = new File(filename);
try {
fis = new FileInputStream(file);
System.out.println("Total file size to read (in bytes) : "
+ fis.available());
int content;
while ((content = fis.read()) != -1) {
// convert to char and display it
System.out.print((char) content);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null)
fis.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
Book should implement Serializable
Check the API
https://docs.oracle.com/javase/7/docs/api/java/io/ObjectOutputStream.html#writeObject%28java.lang.Object%29
Also, remove the out member from Book class because it's not Serializable either.

Java 1.8 FileOutputStream Creating a Directory

I seem to be having a problem with the 1.8 JDK this project was built using the 1.7 JDK but i'm having a problem i can't quite understand.
So i have a ConfigReader Class.
public class ConfigReader {
private static ConfigReader _inst;
public static ConfigReader GetInstance(){
if(_inst == null){
_inst = new ConfigReader();
}
return _inst;
}
private String basePath = "Config/";
public <T extends Serializable> void Write(T in, String filename)
{
String path = basePath+filename+".bin";
try
{
File f = new File(path);
f.mkdirs();
FileOutputStream fileOut =
new FileOutputStream(path);
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(in);
out.close();
fileOut.close();
System.out.println("Saved config file '"+path+"'");
}catch(IOException i)
{
System.out.println("Failed to create config file '"+path+"'");
}
}
public boolean ConfigExists(String filename)
{
String path = basePath+filename+".bin";
File finfo = new File(path);
return finfo.exists();
}
public <T extends Serializable> T Read(T readin, String filename)
{
String path = basePath+filename+".bin";
try
{
FileInputStream fileIn = new FileInputStream(path);
ObjectInputStream in = new ObjectInputStream(fileIn);
readin = (T) in.readObject();
in.close();
fileIn.close();
return readin;
}catch(IOException i)
{
System.out.println("Failed to read '"+path+"'");
return null;
}catch(ClassNotFoundException c)
{
System.out.println("Failed to unserialize '"+path+"'");
c.printStackTrace();
return null;
}
}
}
But for some reason when the Write Method is called it's creating directories E.G
Reading a file:
boolean cfgExists = ConfigReader.GetInstance().ConfigExists("Global.cfg");
if(_inst == null && !cfgExists){
_inst = new Global();
}else if(cfgExists){
_inst = ConfigReader.GetInstance().Read(_inst, "Global.cfg");
}
Writing a file:
ConfigReader.GetInstance().Write(this, "Global.cfg");
I end up with the empty directory "Global.cfg.bin" not a file. i'm slightly confused why this is now happening...
Your call to f.mkdirs() is creating the directory with a path that is identical to your intended file path. Call f.getParentFile().mkdirs() instead and that should clear it up.

Serializing objects with hashMap

This is my first time i try objects serializing.
My problem is that when i call for saving new objects(Reminder.java objects) it saves them in the hash map but when i load it gives me the properties of the last saved object.
So my question is:
1.Saving - How do i "append" objects to a file ?
2.Loading - how to iterate through them and get the right object (using the key class type MyDateClass)
. Example will be welcomed. Thank you.
public void save(MyDateClass chosenDate, String string){
System.out.println("Trying to save");
reminderMap.put(chosenDate, string);
//serializing an object :
this.dateReminder = chosenDate;
this.reminder = string;
try
{
FileOutputStream fileOut =
new FileOutputStream("/tmp/reminder.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(this);
out.close();
fileOut.close();
System.out.printf("Serialized data is saved in /tmp/reminder.ser. ");
}catch(IOException i)
{
i.printStackTrace();
}
}
public String Load(MyDateClass chosenDate){
System.out.println("Trying to load");
this.reminder = reminderMap.get(chosenDate);
System.out.println(this.reminder);
// deserialize
Reminder e = null;
try
{
FileInputStream fileIn = new FileInputStream("/tmp/reminder.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
e = (Reminder) in.readObject();
in.close();
fileIn.close();
}catch(IOException i)
{
i.printStackTrace();
}catch(ClassNotFoundException c)
{
c.printStackTrace();
}
return e.reminder;
}
}
I did a demo and unit test for you, currently I use java.util.Date to substitute your SomeDate class .
update: 2013-12-31
I am not trying to make things complex,but I really feel it is my responsibility to not mislead others,so I try to fixed the code again.Currently, HashMap can't be append,please improve it.Thanks!
this code refactored from your code:
import java.io.*;
import java.util.*;
/**
* refactored by your code
* append object stream haven't realized,please help
* 2013-12-31
*/
public class Reminder implements Serializable {
public static void main(String[] args) {
//do some initialization
Reminder re = new Reminder();
re.put(new Date(System.currentTimeMillis()), "Hope it work!");
re.put(new Date(System.currentTimeMillis()+100), "it work!");
re.put(new Date(System.currentTimeMillis()+200), "Wake up!");
//save to file ,using append mode
String filpath = "/tmp/reminder.ser";
re.save(filpath,true);
//load from file and iterate the key-value pair
Reminder reLoad = Reminder.Load(filpath);
if(reLoad != null) {
Iterator<Map.Entry<Date,String>> it = reLoad.entrySet().iterator();
while(it.hasNext()) {
Map.Entry<Date,String> entry = it.next();
System.out.format("reminder: %tc---%s%n",entry.getKey(),entry.getValue());
}
}
}
public Set<Map.Entry<Date,String>> entrySet() {
return reminderMap.entrySet();
}
public void put(Date chosenDate, String string) {
reminderMap.put(chosenDate, string);
}
public String get(Date chosenDate) {
return reminderMap.get(chosenDate);
}
/**
* serializing an object
* #param filePath path to save file
* #param append indicate whether append or not
*/
public void save(String filePath,boolean append){
System.out.println("Trying to save");
try
{
ObjectOutputStream out = new ObjectOutputStream
( new FileOutputStream(filePath,append));
out.writeObject(this);
out.close();
System.out.printf("Serialized data is saved in "+filePath);
}catch(IOException e)
{
e.printStackTrace();
}
}
/**
* deserialize ,load from file and rebuild object
* #param filePath the path from where to load
* #return a new Object
*/
public static Reminder Load(String filePath) {
System.out.println("Trying to load");
Reminder reminder = null;
try
{
ObjectInputStream in = new ObjectInputStream
(new FileInputStream(filePath));
reminder = (Reminder) in.readObject();
in.close();
}catch(IOException | ClassNotFoundException e)
{
e.printStackTrace();
}
return reminder;
}
private static final long serialVersionUID = 1L;
private Map<Date,String> reminderMap = new HashMap<>();
}

File Structured Error [duplicate]

This question already has an answer here:
StreamCorruptedException: invalid type code: AC
(1 answer)
Closed 5 years ago.
sorry to bother you, once again I need help on the Java language , more precisely on the file structured as the title .
The error in question is that after you have stored more than once , I read reports an error (of course putting in append mode) , and does so even if I do all in the main program ...
My program consists of three classes in three files:
Alluno.java:
import java.io.Serializable;
class Alunno implements Serializable {
private String nome, cognome, data_nascita, indirizzo, residenza, telefono;
public Alunno() {
nome = ""; cognome = ""; data_nascita = ""; indirizzo = ""; residenza = ""; telefono = "";
}
public void setNome(String nome) {
this.nome = nome;
}
void setCognome(String cognome) {
this.cognome = cognome;
}
void setData_Nascita(String data_nascita) {
this.data_nascita = data_nascita;
}
void setIndirizzo(String indirizzo) {
this.indirizzo = indirizzo;
}
void setResidenza(String residenza) {
this.residenza = residenza;
}
void setTelefono(String telefono) {
this.telefono = telefono;
}
}
File.java:
import java.io.*;
class File {
private int dim;
public Alunno nuovoAlunno() throws IOException {
BufferedReader t = new BufferedReader(new InputStreamReader(System.in));
Alunno a = new Alunno();
System.out.println("***Inserimento nuovo alunno***");
System.out.format("Nome: ");
a.setNome(t.readLine());
System.out.format("Cognome: ");
a.setCognome(t.readLine());
System.out.format("Data di nascita: ");
a.setData_Nascita(t.readLine());
System.out.format("Indirizzo: ");
a.setIndirizzo(t.readLine());
System.out.format("Residenza: ");
a.setResidenza(t.readLine());
System.out.format("Telefono: ");
a.setTelefono(t.readLine());
return a;
}
public void sciviFile(Alunno a) {
try {
FileOutputStream f = new FileOutputStream("istituto.dat", true);
ObjectOutputStream fOUT = new ObjectOutputStream(f);
fOUT.writeObject(a);
fOUT.flush();
fOUT.close();
} catch (Exception e) {
System.out.println("Eccezione scrittura: " + e.getMessage());
}
}
public void leggiFile() {
Alunno a;
try {
FileInputStream f = new FileInputStream("istituto.dat");
ObjectInputStream fIN = new ObjectInputStream(f);
while (true) {
try {
a = (Alunno) fIN.readObject();
dim++;
System.out.println("Dimensione file: " + dim);
} catch (EOFException e) {
break;
}
}
f.close();
} catch (Exception e) {
System.out.println("Eccezione lettura: " + e.getMessage());
}
}
}
IstitutoScolastico.java:
import java.io.*;
public class IstitutoScolastico {
public static void main(String[] args) throws IOException {
File f = new File();
//f.sciviFile(f.nuovoAlunno());
f.leggiFile();
}
}
OUTPUT:
Dimensione file: 1
Eccezione lettura: invalid type code: AC
I do not read more than one object if I put in append mode, where did I go wrong?
Ah, anyway sorry for the grammatical errors, but I'm Italian and I helped with google translate!
The problem is that ObjectOutputStream writes a header to the file in it's constructor.
Since you call the constructor for each Alunno you append, you write a new header to the file too.
However ObjectInputStream expects only one header(at the start of the file).
If you don't want to change much in your code, you should create a new ObjectInputStream for each Alunno you read, change the code in your File class:
public void leggiFile() {
Alunno a;
try {
FileInputStream f = new FileInputStream("istituto.dat");
try {
while (true) {
// the header is read in the constructor
ObjectInputStream fIN = new ObjectInputStream(f);
a = (Alunno) fIN.readObject();
dim++;
System.out.println("Dimensione file: " + dim);
}
} catch (EOFException e) { }
f.close();
} catch (Exception e) {
System.out.println("Eccezione lettura: " + e.getMessage());
}
}
A alternative would be to skip 2(?) shorts (4(?) bytes) from the FileInputStream, but if the definition of the header should change (although this seems unlikely), you might have to change your code.
Another alternative would be to read all the Alunnos that are already in the file and then write all Alunnos (including the new one) to the File starting at the beginning of the file. But this may not be as fast as you wish.
For detailed information you can read http://docs.oracle.com/javase/7/docs/platform/serialization/spec/output.html and http://docs.oracle.com/javase/7/docs/platform/serialization/spec/input.html
One last tip: If you use Java SE 7 (or higher) consider using try-with-resources for your streams.

Categories

Resources