I have an arraylist of a certain POJO object that implements serializable. When I write the object to disk I do it like so:
File outputDir = context.getCacheDir();
File outputFile = new File(outputDir, getCacheKey() );
ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(outputFile)));
oos.writeObject(arraylistOfMyObjects);
oos.close();
and when I later want to read back this list into an arraylist of the object, I do it like so:
File outputDir = context.getCacheDir();
File outputFile = new File(outputDir, getCacheKey() );
ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(outputFile)));
final ArrayList<myObject> list = (ArrayList<myObject>) ois.readObject();
ois.close();
I'm receiving frequent exceptions on the line where I cast the inputstream to an arraylist, with the error looking like this:
java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.io.ObjectStreamClass
Why are these errors occurring and how can I change my code to resolve them?
Interestingly enough the error doesn't occur every time I run the app, but only every now and again for whatever weird reason.
Make sure you're writing and reading your objects back in the same order every time. In my case I realized I was writing to the file with optional parameters like this:
if(cacheAllItems) { // <-- BREAKS READING FILE WHEN FALSE
objectOutputStream.writeObject(itemsList);
objectOutputStream.writeObject(itemNamesList);
}
objectOutputStream.writeObject(currentItem);
Then I was attempting to read the file with:
itemsList = (ArrayList<Item>) objectInputStream.readObject(); // MIGHT NOT EXIST
itemNames = (ArrayList<String>) objectInputStream.readObject(); // MIGHT NOT EXIST
currentItem = (Item) objectInputStream.readObject();
So if I had last run my cacheItems() function with the cacheAllItems = true, everything worked fine, but if it had last run just saving currentItem, the readObject() attempted to read the one object as the list that should come first.
Related
Is there someone who know how to read decrypted file without rewrite it into the original file?
After downloading the file, the file automatically encrypted. When I want to open the file, the file will be decrypted first but the problem is how to read the file from CipherInputStream so that no need to convert the file back to the original.
void decrypt(File file1, String nama) throws IOException, NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException {
md5 hash = new md5();
String sapi = hash.md5(nama);
FileInputStream fis = new FileInputStream(file1+ "/" + sapi);
FileOutputStream fos = new FileOutputStream(file1 + "/decrypted.json");
SecretKeySpec sks = new SecretKeySpec("MyDifficultPassw".getBytes(),
"AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, sks);
CipherInputStream cis = new CipherInputStream(fis, cipher);
int b;
byte[] d = new byte[8];
while ((b = cis.read(d)) != -1) {
fos.write(d, 0, b);
}
fos.flush();
fos.close();
cis.close();
}
I can open the decrypted file but it will duplicate between encrypted and original if I use the code above.
FileOutputStream fos = new FileOutputStream(file1 + "/decrypted.json");
writes to the File object passed in as the first parameter to the decrypt method
decrypt(File file1 ...
Which is also the file object you are reading in.
So when you do fos.write(d, 0, b);you are writing back to that File object which is the same object that you are reading from.
So either write to a different file or just don't write anything out at all.
The new FileOutputStreammethod can take a file name instead of a File object as described here Relevant excerpt states
FileOutputStream (String name,
boolean append)
Creates a file output stream to write to the file with the specified
name. If the second argument is true, then bytes will be written to
the end of the file rather than the beginning. A new FileDescriptor
object is created to represent this file connection.
First, if there is a security manager, its checkWrite method is called
with name as its argument.
If the file exists but is a directory rather than a regular file, does
not exist but cannot be created, or cannot be opened for any other
reason then a FileNotFoundException is thrown.
so maybe you want FileOutputStream fos = new FileOutputStream("/decrypted.json", true|false)
setting the second parameter to either true or false depending on whether or not you want the file appended to or overwritten?
It's a little difficult to provide an exact solution to your problem as you don't clearly state what your desired result is so I have made some assumptions which may be wrong but either way the above should help you find the solution you need
I'm downloading lot of images from Internet and storing into a hashmap and showing in a ListView. I want to cache the images. For that, I am storing the Hashmap object into a file inside onDestroy() of my activity and getting back the object inside oncreate().
Map<String, Drawable> hashmap; //storing the urls of images and downloaded image `Drawables` into this map
Inside onCreate():
File f = new File(Environment.getExternalStorageDirectory()+"/image_cache.ser");
if(f.exists()){
FileInputStream fin = new FileInputStream(f);
ObjectInputStream ois = new ObjectInputStream(fin);
hashmap = (HashMap<String, Drawable>)ois.readObject();
ois.close();
Here creating a custom adapter and showing the hashmap drawable images in a listview
}
Inside onDestroy()
#Override
protected void onDestroy() {
super.onDestroy();
File f = new File(Environment.getExternalStorageDirectory()+"/image_cache.ser");
try {
if(hashmap != null && hashmap.size() >= 1){
FileOutputStream fout = new FileOutputStream(f);
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject(hashmap);
oos.flush();
oos.close();
}
} catch (Exception e) {
e.printStackTrace();
f.delete();
}
}
Problem : Getting this exception:
java.io.NotSerializableException android.graphics.drawable.BitmapDrawable inside ondestoy().
Why the hashmap object is not getting serialized ? Where i am going wrong. Could you please put me in a correct way if I'm wrong to cache images?
you can not write your hashmap because the class Drawable is not Serializable
Drawable does not implement Serializable
It just won't work this way. The errors says, that you are trying to serialize a Drawable, which is not implemented, since there are factories to do so in different ways. There is no simple solution with this hashmap.
I have a method which I have an array of String objects which I need to write to a ByteArrayOutputStream which later on I will write into a ZipOutputStream.
Here is my code.
// SAVE THE STRING AS A BYTE ARRAY IN MEMORY INSTEAD OF CREATING AND SAVING TO A NEW FILE
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream byteOut = new DataOutputStream(baos);
byte[] data;
if (i == 1) {
if (nodeStringArray != null) {
for (String s : nodeStringArray) {
byteOut.write(s.getBytes("UTF-8"));
}
}
} else {
data = stringArray.get(i).getBytes("UTF-8");
byteOut.write(data);
}
byteOut.close();
byte[] input = baos.toByteArray();
ZipEntry entry = new ZipEntry(fileName);
entry.setSize(input.length);
zos.putNextEntry(entry);
zos.write(input);
zos.closeEntry();
The issue is, and I have only received on crash report for it, I am getting an OutOfMemoryError on the line that reads byteOut.write(s.getBytes("UTF-8"));
Anyone know of a better way of doing this or can see if I am doing something wrong?
IDEA
Could I put a try catch statement around the problem and when it happens call byteOut.flush()?
Thanks in advance
You are making to many copies of the data, and this is causing you to run out of memory.
You should be directly writing into your ZipOutputStream in your first loop.
ZipEntry entry = new ZipEntry(fileName);
zos.putNextEntry(entry);
for (String s : nodeStringArray) {
zos.write(s.getBytes("UTF-8"));
}
zos.closeEntry();
I want to read/write data dictionary in file which is in android internal/external memory. In WP7, they have used IsolatedStorage for storing the dictionary directly. In IOS, they can write NSDictionary directly to the file. Please anyone tell me the way to write DataDictionary into file.
Note: I have the keys and values in the Map variable.
how to store this Map directly to file
I would suggest putting your words into a database for the following reasons
DB lookups on android with SQLite are "fast enough" (~1ms) for even
the most impatient of users
Reading large files into memory is a dangerous practice in
memory-limited environments such as android.
Trying to read entries out of a file "in place" rather than "in
memory" is effectively trying to solve all the problems that SQLite
already solves for you.
Embed a database in the .apk of a distributed application [Android]
You can find more detailed examples by searching object serialization
[EDIT 1]
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);
[EDIT 2]
try {
File file = new File(getFilesDir() + "/map.ser");
Map map = new HashMap();
map.put("1", new Integer(1));
map.put("2", new Integer(2));
map.put("3", new Integer(3));
Map anotherMap = null;
if (!file.exists()) {
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(map);
oos.close();
System.out.println("added");
} else {
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
anotherMap = (Map) ois.readObject();
ois.close();
System.out.println(anotherMap);
}
} catch (Exception e) {
}
[EDIT 3]
Iterator myVeryOwnIterator = meMap.keySet().iterator();
while(myVeryOwnIterator.hasNext()) {
String key=(String)myVeryOwnIterator.next();
String value=(String)meMap.get(key);
// check for value
}
I'm unsure if using SharedPreferences (link) is something that is suitable for your usecase.
You store via a key-value pair, and can have multiple SharedPreferences per application. While both are stored as String objects, the value can be automatically cast to other primitives using built in methods.
Mark Murphy has written a library, cwac-loaderex (link), to facilitate access of SharedPreferences via the use of the Loader pattern (link), which offsets some of the work you need to do to keep IO off the main thread.
I want to write a serializable object to file in internal memory. Then, I want to load that object back from that file later. How could I do this in Android?
First of all your object must implement Serializable. Don't forget to add a serialVersionUID on the serializable class.
Then if you don't want to save specific field of the object mark it as transient.
Be sure all fields are serializable.
Next create a file in the internal memory and create an ObjectOutputStream to save your object. If you want to save in a specific folder you can create a path like this:
File path=new File(getFilesDir(),"myobjects");
path.mkdir();
Then you can use that path to save your object:
File filePath =new File(path, "filename");
FileOutputStream fos = new FileOutputStream(filePath);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(object);
oos.close();
Reading is similar:
FileInputStream fis = new FileInputStream(file);
ObjectInputStream in = new ObjectInputStream(fis);
MyObjectClass myObject = (MyObjectClass ) in.readObject();
in.close();