This is my first attempt at serializing/deserializing objects on any platform and, to put it mildly, I'm confused.
After implementing Serializable to my game object I output it to a file thus:
public void saveGameState(){
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ObjectOutput out = new ObjectOutputStream(bos);
out.writeObject(theGame);//theGame is an instance of the custom class
//TGame which stores game info.
byte[] buf = bos.toByteArray();
FileOutputStream fos = this.openFileOutput(filename,
Context.MODE_PRIVATE);
fos.write(buf);
fos.close();
} catch(IOException ioe) {
Log.e("serializeObject", "error", ioe);
}
File f =this.getDir(filename, 0);
Log.v("FILE",f.getName());
}
This seems to work, in that I get no exceptions raised. I can only know for sure when I deserialize it. Which is where things go pear shaped.
public God loadSavedGame(){
TGame g=null;
InputStream instream = null;
try {
instream = openFileInput(filename);
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
}
try {
ObjectInputStream ois = new ObjectInputStream(instream);
try {
g= (TGame) ois.readObject();
return g;
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
} catch (StreamCorruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
I got the basis of this code from here Android Java -- Deserializing a file on the Android platform and tried to modify it for my app. When running I get
05-31 23:30:45.493: ERROR/copybit(1279): copyBits failed (Invalid argument)
When the output should be loaded and the saved game start up from when it was saved.
Any help would be appreciated.
The error you've shown is not at all related to serialization: its actually a video display error. I'd suggest looking at the object BEFORE you serialize to make sure its not null, and I'd also suggest serializing to a file on the SD card to make sure you actually had data output (so use new FileOutputStream("/mnt/sdcard/serializationtest") as the output stream and new FileInputStream("/mnt/sdcard/serializationtest") as the input stream) while you are debugging; you can switch back to the context methods after it works, but make sure your sdcard is plugged in while you are doing this.
Finally, modify your logging to look like this:
try {
ObjectInputStream ois = new ObjectInputStream(instream);
try {
g= (TGame) ois.readObject();
return g;
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
android.util.Log.e("DESERIALIZATION FAILED (CLASS NOT FOUND):"+e.getMessage(), e);
e.printStackTrace();
return null;
}
} catch (StreamCorruptedException e) {
android.util.Log.e("DESERIALIZATION FAILED (CORRUPT):"+e.getMessage(), e);
// TODO Auto-generated catch block
e.printStackTrace();
return null;
} catch (IOException e) {
android.util.Log.e("DESERIALIZATION FAILED (IO EXCEPTION):"+e.getMessage(), e);
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
and see what error gets returned. I expect the serialization is failing somehow.
To seralize or deserialize anything you can use SIMPLE api. It is very easy to use. Download the file and use it in your program
Have a look here
http://simple.sourceforge.net/download/stream/doc/tutorial/tutorial.php#deserialize
Thanks Deepak
I have created below class to do the save and retrieve object.
public class SerializeUtil {
public static <T extends Serializable> void saveObjectToFile(Context context, T object, String fileName){
try {
FileOutputStream fos = context.openFileOutput(fileName, Context.MODE_PRIVATE);
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(object);
os.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static<T extends Serializable> T getObjectFromFile(Context context, String fileName){
T object = null;
try {
FileInputStream fis = context.openFileInput(fileName);
ObjectInputStream is = new ObjectInputStream(fis);
object = (T) is.readObject();
is.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return object;
}
public static void removeSerializable(Context context, String filename) {
context.deleteFile(filename);
}
}
Related
I am building an articles reading android application like TechChurn. I am fetching data from server in the form of json.
I am parsing Id(unique),title, author name and articles-content from json and displaying it in list-view.
Those parsed content is stored in local for accessing without internet access.
This i have done using a cache function.
Here is my code that is using for caching -
public final class CacheThis {
private CacheThis() {
}
public static void writeObject(Context context, String fileName,
Object object) throws IOException {
FileOutputStream fos;
ObjectOutputStream oos;
if (fileExistance(fileName, context)) {
fos = context.openFileOutput(fileName, Context.MODE_PRIVATE
| Context.MODE_APPEND);
oos = new AppendingObjectOutputStream(fos);
} else {
fos = context.openFileOutput(fileName, Context.MODE_PRIVATE
| Context.MODE_APPEND);
oos = new ObjectOutputStream(fos);
}
oos.writeObject(object);
oos.flush();
oos.close();
fos.close();
}
public static List<Object> readObject(Context context, String fileName) {
List<Object> list = new ArrayList<Object>(0);
FileInputStream fis;
try {
fis = context.openFileInput(fileName);
ObjectInputStream ois = new ObjectInputStream(fis);
Object object;
try {
while (true) {
object = ois.readObject();
list.add(object);
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return list;
}
public static boolean fileExistance(String fname, Context context) {
File file = context.getFileStreamPath(fname);
return file.exists();
}
}
my article should be cached based on id instead its been loaded for every-time when app is started
Use the following methods to store and retrieve the data.. Here you can store the object..
private void writeData(Object data, String fileName) {
try {
FileOutputStream fos = context.openFileOutput(fileName,
Context.MODE_PRIVATE);
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(data);
os.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public Object readData(String fileName){
Object data = null;
if (context != null) {
try {
FileInputStream fis = context.openFileInput(fileName);
ObjectInputStream is = new ObjectInputStream(fis);
data = is.readObject();
is.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (StreamCorruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return data;
}
Write the data once you got the response from the server(at first request to the server). Use the id as file name. After that check for the particular file before you want to hit server for data. If the file is available then you can get the data from that file, otherwise hit the server.
public void loadprev()
{
String tempread;
try {
FileInputStream fis = openFileInput("data.gds");
try {
fis.read(tempread.getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
my program crashes upon trying to execute fis.read(tempread.getBytes());
i want to read the first line in data.gds and put it into a string, how can i do this?
and no, im not going to use SharedPreferences
add a string buffer and then read from it everyline will be put in the Stringbuffer, then you can retrieve the line from that buffer.
StringBuffer fileContent = new StringBuffer("");
byte[] buffer = new byte[1024];
while ((n = fis.read(buffer)) != -1)
{
fileContent.append(new String(buffer, 0, n));
}
Also, if you are not catching exceptions properly, surround them in 1 try catch, but try to catch them in the future:
{
String tempread;
try {
FileInputStream fis = openFileInput("data.gds");
fis.read(tempread.getBytes());
fis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
now your code is easier to read.
here is the code :
my mission is to serialize an my object(Person) , save it in a file in android(privately), read the file later,(i will get a byte array), and deserialize the byta array.
public void setup()
{
byte[] data = SerializationUtils.serialize(f);
WriteByteToFile(data,filename);
}
Person p =null ;
public void draw()
{
File te = new File(filename);
FileInputStream fin = null;
try {
fin=new FileInputStream(te);
byte filecon[]=new byte[(int)te.length()];
fin.read(filecon);
String s = new String(filecon);
System.out.println("File content: " + s);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
text(p.a,150,150);
}
and my function :
public void WriteByteToFile(byte[] mybytes, String filename){
try {
FileOutputStream FOS = openFileOutput(filename, MODE_PRIVATE);
FOS.write(mybytes);
FOS.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("done");
}
it is returning a filenotfoundexception .
(i am new at this, so please be patient and understanding)
EDIT ::this is how i am (trying to ) read, (for cerntainly)
ObjectInputStream input = null;
String filename = "testFilemost.srl";
try {
input = new ObjectInputStream(new FileInputStream(new File(new File(getFilesDir(),"")+File.separator+filename)));
} catch (StreamCorruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
Person myPersonObject = (Person) input.readObject();
text(myPersonObject.a,150,150);
} catch (OptionalDataException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
input.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
and for reading :::
if(mousePressed)
{
Person myPersonObject = new Person();
myPersonObject.a=432;
String filename = "testFilemost.srl";
ObjectOutput out = null;
try {
out = new ObjectOutputStream(new FileOutputStream(new File(getFilesDir(),"")+File.separator+filename));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
out.writeObject(myPersonObject);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
You don't need to use the 'byte array' approach. There is an easy way to (de)serialize objects.
EDIT: here's the long version of code
Read:
public void read(){
ObjectInputStream input;
String filename = "testFilemost.srl";
try {
input = new ObjectInputStream(new FileInputStream(new File(new File(getFilesDir(),"")+File.separator+filename)));
Person myPersonObject = (Person) input.readObject();
Log.v("serialization","Person a="+myPersonObject.getA());
input.close();
} catch (StreamCorruptedException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
Write:
public void write(){
Person myPersonObject = new Person();
myPersonObject.setA(432);
String filename = "testFilemost.srl";
ObjectOutput out = null;
try {
out = new ObjectOutputStream(new FileOutputStream(new File(getFilesDir(),"")+File.separator+filename));
out.writeObject(myPersonObject);
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Person class:
public class Person implements Serializable {
private static final long serialVersionUID = -29238982928391L;
int a;
public int getA(){
return a;
}
public void setA(int newA){
a = newA;
}
}
FileNotFoundException when creating a new FileOutputStream means that one of the intermediate directories didn't exist. Try
file.getParentFile().mkdirs();
before creating the FileOutputStream.
Add this code to manifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
Go to phone setting/applications/your_app/permissions/ allow files and media permission. You can ask permission via by code and when user enter app program will ask permission. If you want I can give you code.
All writen and readen objects must be serializable.(Must implements Serializable interface) If A class extends B class, to set B class serializable is enough.
And add this code to writen and readen class:
private static final long serialVersionUID = 1L;
Write to external memory:
public static void writeToExternal(Serializable object, String filename) {
try {
//File root = new File(Environment.getExternalStorageDirectory(), "MyApp");
//or
File root = new File("/storage/emulated/0/MyApp/");
if (!root.exists()) {
root.mkdirs();
}
File file = new File(root, filename);
FileOutputStream fos = new FileOutputStream(file);
ObjectOutput out = new ObjectOutputStream(fos);
out.writeObject(object);
out.flush();
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
If you want to write to internal memory(This memory is not visible and doesn't need permission. This is your app stored in. For this, you can use getFilesDir() instead of getExternalStorageDirectory(). More about https://developer.android.com/reference/android/content/ContextWrapper#getFilesDir%28%29
https://developer.android.com/reference/android/os/Environment.html#getDataDirectory%28%29
https://gist.github.com/granoeste/5574148
https://source.android.com/docs/core/storage
public static void writeToInternal(Context context, Serializable object, String filename){
try {
//File root1 = new File(context.getFilesDir(), "MyApp");
//or
File root = new File("/data/user/0/com.example.myapplication/files/MyApp/");
if (!root.exists()) {
root.mkdirs();
}
File file = new File(root, filename);
FileOutputStream fos = new FileOutputStream(file);
ObjectOutput out = new ObjectOutputStream(fos);
out.writeObject(object);
out.flush();
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Read an object:
public static Object read(String filename) {
try {
File file = new File("/storage/emulated/0/MyApp/" + filename);
FileInputStream fis = new FileInputStream(file);
ObjectInputStream input = new ObjectInputStream(fis);
Object data = (Object) input.readObject();
input.close();
return data;
} catch (StreamCorruptedException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
When you call read method you must cast to your readen and writen class.(For example Person p = (Person)read("file.txt");
Import all classes and run.
I want my app to hold data from ArrayList in file in between sessions. Class I use implements Serializable. When I debug saving seems to go OK, with no exceptions thrown, and going through the loop the right amount of times. Loading loads just some of entries and then throws EOF Exception. The code is here:
public int saveChildren(Context context){
FileOutputStream fos;
ObjectOutputStream os;
try {
fos = context.openFileOutput(filename, Context.MODE_PRIVATE);
os = new ObjectOutputStream(fos);
for(Child c : children){
os.writeObject(c);
}
os.close();
}
catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return 1;
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return 2;
}
return 0;
}
public void loadChildren(Context context){
FileInputStream fis;
try {
fis = context.openFileInput(filename);
ObjectInputStream is;
is = new ObjectInputStream(fis);
while(is.readObject() != null){
Child c = (Child) is.readObject();
boolean skip = false;
for(Child ch: children){
if(ch.getName().equals(c.getName())){
skip = true;
}
if(ch.getNr().equals(c.getNr())){
skip = true;
}
if(ch.getImei() != null){
if(ch.getImei().equals(c.getImei())){
skip = true;
}
}
}
if(!skip){
children.add(c);
}
}
is.close();
}catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (StreamCorruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}catch (OptionalDataException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
What causes the errors?
You can directly write the children object into the ObjectOutputStream. ArrayList implements serializable. A second thing you might want to do is flush the stream before closing it with os.flush(). You will have:
os = new ObjectOutputStream(fos);
os.writeObject(children);
os.flush();
os.close();
and for reading:
is = new ObjectInputStream(fis);
ArrayList<Child> children = (ArrayList<Child>)is.readObject();
is.close();
You're using ObjectInputStream#readObject() returning null as an exit condition for your loop. #readObject() can return null - if you've serialized a null - it will however throw an exception if it fails to read an object because you've reached the end of the stream.
For a quick and easy fix: Consider serializing the length of the array as an integer before serializing the children & use a for-loop or similar construct to read the values - or serializing the ArrayList itself. It's also Serializable.
I'm so confused. After reading this thread, I'm trying to write a List to internal storage onPause(), then read the List onResume(). Just for testing purposes, I'm trying to write a simple string as the example showed. I've got this to write with:
String FILENAME = "hello_file";
String string = "hello world!";
FileOutputStream fos = null;
try {
fos = openFileOutput(FILENAME, Context. MODE_WORLD_READABLE);
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
fos.write(string.getBytes());
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
fos.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
And I'm trying to read it in onResume() by calling:
try {
resultText01.setText(readFile("hello_file"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
resultText01.setText("exception, what went wrong? why doesn't this text say hello world!?");
}
Which of course uses this:
private static String readFile(String path) throws IOException {
FileInputStream stream = new FileInputStream(new File(path));
try {
FileChannel fc = stream.getChannel();
MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
/* Instead of using default, pass in a decoder. */
return Charset.defaultCharset().decode(bb).toString();
}
finally {
stream.close();
}
}
For some reason, resultText01.setText(...) isn't being set to "hello world!", and is instead calling the catch exception. I'm sorry if my lingo isn't correct, I'm new to this. Thanks for any pointers.
Instead of the following in your readFile(...) method...
FileInputStream stream = new FileInputStream(new File(path));
Try...
FileInputStream stream = openFileInput(path);