I'm creating a game where all locations of 'blocks' are stored in the variable block_area - an object of class Area. My game has been running correctly for a week now, and I've decided to implement a save and load feature where I save block_area to a file Drifter, with this as my code:
Area block_area; // Later initialized
void saveArea()
{
try
{
FileOutputStream fos = new FileOutputStream(savefile);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(block_area);
oos.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
void loadArea()
{
try
{
FileInputStream fis = new FileInputStream(savefile);
ObjectInputStream ois = new ObjectInputStream(fis);
block_area = (Area)ois.readObject();
ois.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
However, this is my very first time writing and reading an OBJECT to a file, so I don't know much about it. When I try to save the object to the file, it gives me this error:
java.io.NotSerializableException: java.awt.geom.Area
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at Drifter.saveArea(Drifter.java:58)
at Drifter.keyPressed(Drifter.java:315)
...
If anyone can tell me how I can go about writing and reading an object with a file, the help will be greatly appreciated.
TL;DR How do I write the contents of an Area object to a file and read it?
ALSO I have a few follow-up questions:
Is ObjectInputStream the best course of action here? I have seen a few answers where people recommend using XML, and JSON, but I can never find the time to learn about them, and would prefer to stick to a pure Java method (without any third party tools)
Is there any other method of saving an object's information to an external source that I can use instead of file handling?
EDIT - I should also mention that my class implements Serializable
The exception is pretty self explanatory NotSerializableException: java.awt.geom.Area . Any object that you want to serialize must implement the Serializable interface. java,awt.geom.Area does not. Any attributes of that class must also implement Serializable, be a primitive, or be defined as transient.
I'd suggest either Figuring out a way to read Area into an object that does implement Serializable. When you read it back out, you can construct a new Area object. This is probably what the JSON/XML method mentioned in the comments is doing. The added benefit of a human readable storage format is that you can edit it in a text editor. You won't be able to do that with the binary output of a serialized object`.
Related
I have a data structure that I would like to be able to write to a file before closing the program, and then read from the file to re-populate the structure the next time the application starts.
My structure is HashMap<String, Object>. The Object is pretty simple; For member variables it has a String, and two small native arrays of type Boolean. This is a real simple application, and I wouldn't expect more than 10-15 <key,value> pairs at one time.
I have been experimenting (unsuccessfully) with Object input/output streams. Do I need to make the Object class Serializable?
Can you give me any suggestions on the best way to do this? I just need a push in the right direction. Thanks!
EDIT: Well I feel dumb still, I was writing from one map and reading into another map, and then comparing them to check my results. Apparently I was comparing them wrong. Sigh.
If you aren't concerned about Object particularly , you just need key value pair of String,String then I would suggest you to go for java.util.Properties. otherwise here you go
Map map = new HashMap();
map.put("1",new Integer(1));
map.put("2",new Integer(2));
map.put("3",new Integer(3));
FileOutputStream fos = new FileOutputStream("map.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(map);
oos.close();
FileInputStream fis = new FileInputStream("map.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
Map anotherMap = (Map) ois.readObject();
ois.close();
System.out.println(anotherMap);
Map m = new HashMap();
// let's use untyped and autoboxing just for example
m.put("One",1);
m.put("Two",2);
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("foo.ser")
);
oos.writeObject(m);
oos.flush();
oos.close();
Yes, your objects will need to implement Serializable in order to be serialized by the default Java mechanism. HashMap and String already implement this interface and thus can be serialized successfully.
Take a look at Sun's own Serialization tutorial - it's quite short and I think should cover everything you need for your simple case. (You should just be able to serialise the Map object to the stream, and then read it back in on subsequent runs).
If you do run into problems, try serializing a simple HashMap<String, String> with some dummy values. If this succeeds, you'll know that the problem lies (somehow) with your own class' serializability; alternatively, if this doesn't work you can focus on the basic structure before throwing your own class into the mix.
Post back if you have any more specific problems that you can't figure out on your own.
Yes, if you want to write an object to the file system, that object must implement Serializeable. Here is a tutorial that should help you out.
Don't bother with making it Serializable until you understand more about what that's used for. You want to look at FileWriter and google "java file io" A good way to write this data is as CSV.
eg.
key1,key2,key3
valuea1,valuea2,valuea3
valueb1,valueb2,valueb3
Hope this helps.
SERIALIZE A HASHMAP:
This code is working fine , I have implemented and used in my app. Plz make ur functions accordingly for saving map and retrieving map.
Imp thing is, you need to make confirm that the objects you are putting as value in map must be serializable , means they should implement serailizbele interface. ex.
Map<.String,String> hashmap=new HashMap<.String,String>().. here in this line ...map and string both are implictly serializable , so we dont need to implement serializble for these explicitly but if you put your own object that must be serializable.
public static void main(String arr[])
{
Map<String,String> hashmap=new HashMap<String,String>();
hashmap.put("key1","value1");
hashmap.put("key2","value2");
hashmap.put("key3","value3");
hashmap.put("key4","value4");
FileOutputStream fos;
try {
fos = new FileOutputStream("c://list.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(hashmap);
oos.close();
FileInputStream fis = new FileInputStream("c://list.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
Map<String,String> anotherList = (Map<String,String>) ois.readObject();
ois.close();
System.out.println(anotherList);
} catch (FileNotFoundException e) {e.printStackTrace();
} catch (IOException e) {e.printStackTrace();
} catch (ClassNotFoundException e) {e.printStackTrace();
}
}
I'd advise against using Serializable; it is much harder to do properly than it first seems. It would seem that simply adding implements Serializable is all you need to do. But in fact this adds many restrictions on your code that are difficult to deal with in practical software development (rather than in school). To see just how horrible these restrictions are, see the book Effective Java (second edition) by Bloch.
I've written my own 3D Game Engine and started writing a game. I am using OBJ-Models that use the TurboSquid Royalty Free License
Basically, it says that I can use their OBJ-Files but have to implement something that avoids the users to extract the OBJ-Files out of my program.
I've written a converter that extracts the information out of the OBJ-File and creates several float/integer arrays [vertices, vertexCoords, normals, tangents..., indices]
These arrays will be used later for creating the VAOs / VBOs. So my idea was to create a Java class called OBJModelData that contains these arrays. OBJModelDataimplements Serializable. My attempt was to save the class into a file and use them instead of the OBJ-File so that the user cannot see and use the content.
My attempt looks like this:
public void writeToFile(String file){
File f = new File(OBJLoader.RES_LOC+ file +".dat");
try {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f));
out.writeObject(this);
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
This results in a file called modelName.dat and looks like this:
Obviously reverse engineering must be done the recreate my arrays. I just do not like the way its written. For example the class that has been serialized is written in the first line. If someone somehow manages the get the source files of my engine by doing some reverse engineering on that he could easily read the file.
Is my method save enough to avoid recreating the obj files and can I still use this method to fulfill the license conditions or is there any other way that is normally used (e.g. in other games/engines) ?
The end of your quote says: "without reverse engineering", so you do not need carry about reverse engineering. You need only "translate" from OBJ to another format of your creation, like you do.
I have an ArrayList of a Serializable, which I can serialize then save and load it from a file. But what if I want to add an object to the arraylist, without loading the whole list, then saving the whole thing again? I don't feel like loading the whole list, then adding an object to it and then save it again, as it would impact my performance.
These are the two method I've made for saving and loading the file. The Deck class of course implements Serializable.
public static List<Deck> loadDeckDatabase() throws IOException, ClassNotFoundException {
FileInputStream fis = new FileInputStream("decks");
ObjectInputStream ois = new ObjectInputStream(fis);
List decList = (List) ois.readObject();
ois.close();
return decList;
}
public static void saveDeckDatabase(List<Deck> decks) throws IOException, ClassNotFoundException {
FileOutputStream fos = new FileOutputStream("decks");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(decks);
oos.close();
}
I hope someone can help me. Thanks!
Either:
You have to load and save, as you don't know how the Deck is serialized.
You can to write your own serialization so you actually know how to append.
See also here:
https://stackoverflow.com/a/7290812/461499
Why don't you just use SQLite database? It is light, local (stored just in file) database supported by Java. The way you are using it is same that using common database.
Look at the tutorial here: http://www.tutorialspoint.com/sqlite/sqlite_java.htm
If you don't want to use the database I see two ways to dealt with you problem:
Keep every array object in other file and keep a files counter in some place - which is not very elegant solution and I guess it will increase I/O operations count
Serialize your structure to JSON and write your own method to add element. Since JSON's structure is very simple it seems to be quite easy to just add new element with simple file and string operations
i am developing a small application in Java. At certain point i need to save the object of my custom class to a text file for this i override toString() method in my custom class and then use ObjectOutputStream class to save object of my custom class to text file. Now everything works fine i.e the text file contains the text as expected. Following three lines contain major code for that
ObjectOutputStream outputStream = null;
outputStream = new ObjectOutputStream(new FileOutputStream(filename));
outputStream.writeObject(person);//person is the instance of my custom class
Now, how do i add some static data to my file along with the object data
outputStream = new ObjectOutputStream(new FileOutputStream(filename));
outputStream.WhatFunctoinToUse("some static text");//What function i use to add static text??
outputStream.writeObject(person);//person is the instance of my custom class
Short answer: You don't.
ObjectOutputStream is not meant to be used in that fashion. It outputs a Serializable object in a format specified by the API. This is not always a good idea, i.e. it is easy to break compatibility in future releases.
Although the format outputted looks readable, it contains a lot of non-printable characters, that adding some static text to probably would break the serialization.
What you are looking for is either:
a) A clear-text serialization such as JSON or XML (Try http://simple.sourceforge.net/, it's really simple)
b) A text file besides your serialized object.
You should NOT try to extend the functionality of the ObjectOutputStream unless you have a very very good reason for it, and it does not seem you have.
If you want to append a primitive type value to be flattened with an Object, pass your ObjectOutputStream to PrintStream to enable you append a new line which will effect hold the static value as require.
See below for both Reading and writing.
//Writting
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("person.out"));
outputStream.writeObject(person);
PrintStream pst = new PrintStream(outputStream);
pst.append("Some static Value");
outputStream.flush();
outputStream.close();
pst.close();
// Reading
ObjectInputStream in = new ObjectInputStream(new FileInputStream("person.out"));
Perrson person=(Person) in.readObject();
String staticText =in.readLine();
in.close();
Hope you realise that by making use of ObjectOutputStream and writing person to it, you're in essence serializing the person object.
I have a collection of objects:
Map<BufferedImage, Map<ImageTransform, Set<Point>>> map
I want to write those to a file, and then be able to read them back in the same struct.
I can't just write the collection as it is, because BufferedImage doesn't implement the Serializable (nor the Externalizable) interface. So I need to use the methods from the ImageIO class to write the image.
ImageTransform is a custom object that implements Serializable. So, I believe the value part of my map collection, should be writeable as it is.
Here is what I do to write to the file:
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
for (BufferedImage image : map.keySet()) {
ImageIO.write(image, "PNG", out); // write the image to the stream
out.writeObject(map.get(image)); // write the 'value' part of the map
}
Here is what I do to read back from the file:
ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
while(true) {
try {
BufferedImage image = ImageIO.read(in);
Map<ImageTransform, Set<Point>> value =
(Map<ImageTransform, Set<Point>>) in.readObject(); // marker
map.put(image, value);
} catch (IOException ioe) {
break;
}
}
However, this doesn't work. I get a java.io.OptionalDataException at marker.
java.io.OptionalDataException
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1300)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:368)
My question is, firstly, is the writing concept correct ? is ImageIO#write good for this case, or should I think about using/storing the BufferedImage#getRgb int[] array ? is the array more compact (as in, takes up less space in the file) ?
Secondly, how should I be reading the object back from the file ? How do I know when the EOF is reached ? Why doesn't the above work ?
I hope the info provided is enough, if you need more info on something, please tell me.
Thanks in advance.
It's not working as ObjectOutputStream and ObjectInputStream write/expect a certain file format that is violated when you write an image out of order. To use ObjectStreams successfully you will need to observe the contract that is specifed by ObjectStreams.
To do this you will need to create a holding class, and use this class as the key to your map instead of BufferedImages. This holding class should implement Serializable and a three methods (not in any actual interface) that mark the Class as needing special handling during reading and writing. The method signatures must be exactly as specified or serialization won't work.
For more information have a look at the documentation on ObjectOutputStream.
public class ImageHolder implements Serializable {
BufferedImage image;
public ImageHolder(BufferedImage image) {
this.image = image;
}
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
image = ImageIO.read(stream);
}
private void writeObject(ObjectOutputStream stream)
throws IOException {
ImageIO.write(image, "PNG", stream);
}
private void readObjectNoData() throws ObjectStreamException {
// leave image as null
}
And then serialsation should be as simple as outputStream.writeObject(map). Though you will need to check that the implementing class of ImageTransform is serialisable too.
One way to 'cheat' and only have a single object to serialize is to add the group of objects to an expandable, serializable list. Then serialize the list.
BTW - I would tend to use XMLEncoder over serialized Objects because they can be restored in later JVMs. There is no such guarantee for serialized Objects.
#Ivan c00kiemon5ter V Kanak: "I'm trying to keep the file as small in size as possible,..
That is often wasted effort, given disk space is so cheap.
*.. so I guess Serialization is better for that. *
Don't guess. Measure.
..I'll try using a List and see how that goes. ..
Cool. Note that if using the XMLEncoder, I'd recommend Zipping it in most cases. That would reduce the file size of the cruft of XML. This situation is different in storing images.
Image formats typically incorporate compression of a type that is not conducive to being further compressed by Zip. That can be side-stepped by storing the XML compressed, and the images as 'raw' in separate entries in the Zip. OTOH I think you'll find the amount of bytes saved by compressing the XML alone is not worth the effort - given the final file size of the image entries.