I'm trying to:
Write an object (or a series of objects of different types/classes) into a file
Read them back
Check the instances and cast them into objects of their same type/class again
I could find these two classes, and this is how I use them. But the data[] array doesn't make much sense to me. Why do you have to put an empty array of data into the deserialize method?
public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(out);
os.writeObject(obj);
return out.toByteArray();
}
public static Object deserialize(byte[] data)
throws IOException, ClassNotFoundException {
ByteArrayInputStream in = new ByteArrayInputStream(data);
ObjectInputStream is = new ObjectInputStream(in);
return is.readObject();
}
public static void main(String[] args) {
try {
Thing p = new Thing(2,4);
byte[]data = new byte[10240];
serialize(p);
Object des = deserialize(data);
} catch (IOException | ClassNotFoundException ex) {
Logger.getLogger(PruebiƱa.class.getName())
.log(Level.SEVERE, null, ex);
}
}
How can I fix this? Now I'm having the following error, when the program reaches the deserialize line:
java.io.StreamCorruptedException: invalid stream header: 00000000
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:806)
What can I do to fix this, and being able to write and read the objects back? And yes, the class Thing is Serializable.
If you want to write to a File you don't need the byte arrays at all use
FileInputStream and FileOutputStream eg.
public static void serialize(Object obj, File f) throws IOException {
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f))) {
out.writeObject(obj);
}
}
public static Object deserialize(File f)
throws IOException, ClassNotFoundException {
try (ObjectInputStream is = new ObjectInputStream(new FileInputStream(f))) {
return is.readObject();
}
}
static class Thing implements Serializable {
int a,b,c;
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
File f = new File("object.dat");
Thing orig = new Thing();
serialize(orig, f);
Thing back = (Thing) deserialize(f);
}
You create the array in serialize, you don't need to create your own array.
Just do this:
byte[] data = serialize(p);
Instead of this:
byte[]data = new byte[10240];
serialize(p);
Related
#Override
public Collection<Flight> getAll() {
try (ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)))) {
Object read = ois.readObject();
List<Flight> objects = (ArrayList<Flight>) read;
return objects;
} catch (IOException | ClassNotFoundException ex) {
ex.printStackTrace();
return new ArrayList<>();
}
}
#Test
public void testGetAll() {
try (ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream("flights.txt")))) {
Object read = ois.readObject();
expected = (ArrayList<Flight>) read;
} catch (IOException | ClassNotFoundException ex) {
ex.printStackTrace();
}
Collection<Flight> actual = flightService.getAll();
assertEquals(expected, actual);
}
Hi I have serious problem with testing. Is the above code a correct way to test? Please help me
So say your class is given the file to read in the constructor, like this:
class FlightReader {
File file;
public FlightReader(File f) {
file = f;
}
// your getAll here
}
then a test would first create a file of its own with known data, then read it, then verify the results are as expected, like this:
#Test
public void testGetAll() {
Flight f1 = new Flight("ACREG1", "B737");
Flight f2 = new Flight("ACREG2", "A320");
Flight f3 = new Flight("ACREG3", "B777");
List<Flight> written = new ArrayList<>(Arrays.asList(f1, f2, f3));
File tempFile = File.createTempFile("flights", "test");
// write sample data
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(tempFile))) {
oos.writeObject(written);
}
// data is written to a file, read it back using the tested code
FlightReader reader = new FlightReader(tempFile);
List<Flight> readFlights = reader.getAll();
// verify the written and read data are the same
assertThat(readFlights).contains(f1, f2, f3);
}
Some notes:
you should use specific classes - like in this case ArrayList - as little as possible. Why cast to an ArrayList if you just return a Collection in the end?
you shouldn't use Java Serialization at all; it's error-prone, a security risk, and considered a mistake by the Java architects.
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 ; )
I want to add lots of data to a file. I defined the HYB class since my object contains ofdifferent types of data (String and byte[]). I used ObjectOutputStream and ObjectInputStream to write and read from the file. But my code does not print the expected result. To write my code I used code in the following pages:
How can I append to an existing java.io.ObjectStream?
ClassCastException when Appending Object OutputStream
I try to debug my code and found the problem but I could not. This is my code:
import java.io.*;
import java.io.BufferedOutputStream;
import java.util.*;
public class HYB implements Serializable
{
private static final long serialVersionUID = 1L;
private List<byte[]> data = new ArrayList<>();
public void addRow(String s,byte[] a)
{
data.add(s.getBytes()); // add encoding if necessary
data.add(a);
}
#Override public String toString()
{
StringBuilder sb = new StringBuilder();
synchronized (data)
{
for(int i=0;i<data.size();i+=2)
{
sb.append(new String(data.get(i)));
sb.append(Arrays.toString(data.get(i+1))+"\n");
}
}
return sb.toString();
}
private static void write(File storageFile, HYB hf)
throws IOException {
ObjectOutputStream oos = getOOS(storageFile);
oos.writeObject(hf);
oos.flush();
oos.close();
}
public static ObjectOutputStream getOOS(File file) throws IOException
{
if (file.exists()) {
return new AppendableObjectOutputStream(new FileOutputStream(file, true));
} else {
return new ObjectOutputStream(new FileOutputStream(file));
}
}
private static ObjectInputStream getOIS(FileInputStream fis)
throws IOException {
long pos = fis.getChannel().position();
return pos == 0 ? new ObjectInputStream(fis) :
new AppendableObjectInputStream(fis);
}
private static class AppendableObjectOutputStream extends
ObjectOutputStream {
public AppendableObjectOutputStream(OutputStream out)
throws IOException {
super(out);
}
#Override
protected void writeStreamHeader() throws IOException {
}
}
private static class AppendableObjectInputStream extends ObjectInputStream {
public AppendableObjectInputStream(InputStream in) throws IOException {
super(in);
}
#Override
protected void readStreamHeader() throws IOException {
// do not read a header
}
}
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException
{
File x=new File ("test");
HYB hf1 = new HYB();
hf1.addRow("fatemeh",new byte[] {11,12,13});
hf1.addRow("andisheh",new byte[] {14,15,16});
write(x,hf1);
HYB hf = new HYB();
hf.addRow("peter",new byte[] {1,2,3});
hf.addRow("jaqueline",new byte[] {4,5,6});
write(x,hf);
FileInputStream fis = new FileInputStream(x);
HYB hf2 = (HYB) getOIS(fis).readObject();
System.out.println(hf2);
}
}
expected results:
fatemeh[11, 12, 13]
andisheh[14, 15, 16]
peter[1, 2, 3]
jaqueline[4, 5, 6]
actual results:
fatemeh[11, 12, 13]
andisheh[14, 15, 16]
Writing the two HYB objects to the ObjectOutputStream doesn't merge them into a single HYB object; the ObjectOutputStream still contains two HYB object, of which your code reads one. If you did a second call to readObject(), the second one would be retrieved and could be printed to the screen. So you could just wrap the readObject() and println() calls in a loop that reads/writes until there's nothing else to read from the stream.
You are writing two HYB objects to the stream, but only reading one out.
You need to readObject() twice.
I am writing a program in Java which displays a range of afterschool clubs (E.G. Football, Hockey - entered by user). The clubs are added into the following ArrayList:
private ArrayList<Club> clubs = new ArrayList<Club>();
By the followng Method:
public void addClub(String clubName) {
Club club = findClub(clubName);
if (club == null)
clubs.add(new Club(clubName));
}
'Club' is a class with a constructor - name:
public class Club {
private String name;
public Club(String name) {
this.name = name;
}
//There are more methods in my program but don't affect my query..
}
My program is working - it lets me add a new Club Object into my arraylist, i can view the arraylist, and i can delete any that i want etc.
However, I now want to save that arrayList (clubs) to a file, and then i want to be able to load the file up later and the same arraylist is there again.
I have two methods for this (see below), and have been trying to get it working but havent had anyluck, any help or advice would be appreciated.
Save Method (fileName is chosen by user)
public void save(String fileName) throws FileNotFoundException {
String tmp = clubs.toString();
PrintWriter pw = new PrintWriter(new FileOutputStream(fileName));
pw.write(tmp);
pw.close();
}
Load method (Current code wont run - File is a string but needs to be Club?
public void load(String fileName) throws FileNotFoundException {
FileInputStream fileIn = new FileInputStream(fileName);
Scanner scan = new Scanner(fileIn);
String loadedClubs = scan.next();
clubs.add(loadedClubs);
}
I am also using a GUI to run the application, and at the moment, i can click my Save button which then allows me to type a name and location and save it. The file appears and can be opened up in Notepad but displays as something like Club#c5d8jdj (for each Club in my list)
You should use Java's built in serialization mechanism.
To use it, you need to do the following:
Declare the Club class as implementing Serializable:
public class Club implements Serializable {
...
}
This tells the JVM that the class can be serialized to a stream. You don't have to implement any method, since this is a marker interface.
To write your list to a file do the following:
FileOutputStream fos = new FileOutputStream("t.tmp");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(clubs);
oos.close();
To read the list from a file, do the following:
FileInputStream fis = new FileInputStream("t.tmp");
ObjectInputStream ois = new ObjectInputStream(fis);
List<Club> clubs = (List<Club>) ois.readObject();
ois.close();
As an exercise, I would suggest doing the following:
public void save(String fileName) throws FileNotFoundException {
PrintWriter pw = new PrintWriter(new FileOutputStream(fileName));
for (Club club : clubs)
pw.println(club.getName());
pw.close();
}
This will write the name of each club on a new line in your file.
Soccer
Chess
Football
Volleyball
...
I'll leave the loading to you. Hint: You wrote one line at a time, you can then read one line at a time.
Every class in Java extends the Object class. As such you can override its methods. In this case, you should be interested by the toString() method. In your Club class, you can override it to print some message about the class in any format you'd like.
public String toString() {
return "Club:" + name;
}
You could then change the above code to:
public void save(String fileName) throws FileNotFoundException {
PrintWriter pw = new PrintWriter(new FileOutputStream(fileName));
for (Club club : clubs)
pw.println(club); // call toString() on club, like club.toString()
pw.close();
}
In Java 8 you can use Files.write() method with two arguments: Path and List<String>, something like this:
List<String> clubNames = clubs.stream()
.map(Club::getName)
.collect(Collectors.toList())
try {
Files.write(Paths.get(fileName), clubNames);
} catch (IOException e) {
log.error("Unable to write out names", e);
}
This might work for you
public void save(String fileName) throws FileNotFoundException {
FileOutputStream fout= new FileOutputStream (fileName);
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject(clubs);
fout.close();
}
To read back you can have
public void read(String fileName) throws FileNotFoundException {
FileInputStream fin= new FileInputStream (fileName);
ObjectInputStream ois = new ObjectInputStream(fin);
clubs= (ArrayList<Clubs>)ois.readObject();
fin.close();
}
ObjectOutputStream.writeObject(clubs)
ObjectInputStream.readObject();
Also, you 'add' logic is logically equivalent to using a Set instead of a List. Lists can have duplicates and Sets cannot. You should consider using a set. After all, can you really have 2 chess clubs in the same school?
To save and load an arraylist of
public static ArrayList data = new ArrayList ();
I used (to write)...
static void saveDatabase() {
try {
FileOutputStream fos = new FileOutputStream("mydb.fil");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(data);
oos.close();
databaseIsSaved = true;
}
catch (IOException e) {
e.printStackTrace();
}
} // End of saveDatabase
And used (to read) ...
static void loadDatabase() {
try {
FileInputStream fis = new FileInputStream("mydb.fil");
ObjectInputStream ois = new ObjectInputStream(fis);
data = (ArrayList<User>)ois.readObject();
ois.close();
}
catch (IOException e) {
System.out.println("***catch ERROR***");
e.printStackTrace();
}
catch (ClassNotFoundException e) {
System.out.println("***catch ERROR***");
e.printStackTrace();
}
} // End of loadDatabase
public Map<String, BarrackData> barrack = new HashMap<String, BarrackData>();
SavingData.save(barrack, "barrack.bin"); // save
barrack = (Map<String, BarrackData>)SavingData.load("barrack.bin"); // load
// BarrackData contains 3 int's and 1 String.
public static void save(Object obj, String path) throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));
oos.writeObject(obj);
oos.flush();
oos.close();
}
public static Object load(String path) throws Exception {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
Object result = ois.readObject();
ois.close();
return result;
}
How can I Save/Load HashMap's.
I use this methode, but it seem's to have problems.
The barrack.bin contains some error's that I can't figure out.
(java.io.NotSerializableException java.io.ObjectStreamException IOException suppressedExceptionst)
Your class BarrackData does not appear to implement java.io.Serializable. It should look like this:
public class BarrackData implements Serializable {
...