This question already has answers here:
How to store HashMap on Android?
(3 answers)
Closed 9 years ago.
I have a HashMap that has been generated in an activity and I want to store it using something similar to SharedPreferences. I've tried to find information and have been referenced to something called GSON but I'm not exactly sure what that is. If I have something like:
HashMap<String, String> hashMap = new HashMap<String, String> ();
hashMap.put("String 1", "Value 1");
hashMap.put("String 2", "Value 2");
How can I store hashMap so that I can then read it in another activity and use that information? It also needs to be stored should the user close the app.
Json is very similar to HasMap. To save a Json you have to use a key and value like HasMap:
JSONObject userDetail = new JSONObject();
userDetail.put("email", email);
userDetail.put("token", token);
After that you can use a FileWriter or FileInputStream to save it in file .json and you can get it from other activitys using a JSONParser.
For more information about json look this
Go with Victor's answer.
But if your hashMap is complex, like(hash inside hash of hash)
you can store it directly in a file and read it later:
Write to file:
public void saveHashToFile(HashMap<String, Object> hash) throws IOException{
String filePath = getApplicationContext().getFilesDir().getPath().toString() + "/your.properties";
File file = new File(filePath);
FileOutputStream f = new FileOutputStream(file);
ObjectOutputStream s = new ObjectOutputStream(f);
s.writeObject(getProperty_Global());
s.close();
}
Reading back from file:
public HashMap<String, Object> getLocalHashFromFile() throws OptionalDataException, ClassNotFoundException, IOException{
String filePath = getApplicationContext().getFilesDir().getPath().toString() + "/your.properties";
File file = new File(filePath);
FileInputStream f = new FileInputStream(file);
ObjectInputStream s = new ObjectInputStream(f);
HashMap<String, Object> hashFromFile=(HashMap<String, Object>) s.readObject();
s.close();
Log.e("hashfromfileLOCAL", ""+hashFromFile);
return hashFromFile;
}
Gson is a Java library for converting Java objects into JSON strings and vice-verse.
I had the same issue in my project, and used Gson for converting the HashMap into a String, saving it into SharedPreferences, and getting it back in another activity.
To store the Map:
SharedPreferences preferences = getSharedPreferences("com.your.package", MODE_PRIVATE);
Type genericType = new TypeToken<HashMap<String, String>>() {}.getType();
String serializedHashMap = Helpers.serializeWithJSON(your_hashmap, genericType);
preferences.edit().putString("Somename", serializedHashMap).commit();
serializeWithJSON():
public static String serializeWithJSON(Object o, Type genericType) {
Gson gson = new Gson();
return gson.toJson(o, genericType);
}
To deserialize:
Gson gson = new Gson();
Type genericType = new TypeToken<HashMap<String, String>>() {}.getType();
HashMap<String, String> hashMap = gson.fromJson(preferences.getString("Somename", "Errormessage"), genericType);
To persistently store it in a file, use amalBit's answer.
Related
I have Arraylist of Points object stored in file as a string. I converted it into string using gson library.
for (final VisionDetRet ret : results) {
ArrayList<Point> landmarks = ret.getFaceLandmarks();
Gson gson = new Gson();
FileWriter writer = new FileWriter(Environment.getExternalStorageDirectory()+"fileName.txt", true);
gson.toJson(landmarks, writer);
writer.close();
}
This store list of points in file like
[{"X":90, "Y":120},{"X":50, "Y":121},...][{"X":90, "Y":120},
{"X":50, "Y":121},...][{"X":90, "Y":120},{"X":50, "Y":121},...]
I want to read string from that file and want to convert back into ArrayList.
You just need to create a TypeToken for the ArrayList with the specific generic type defined.
FileReader reader = new FileReader(Environment.getExternalStorageDirectory()+"fileName.txt");
Type listType = new TypeToken<ArrayList<Point>>() { }.getType();
ArrayList<Point> landmarks = new Gson().fromJson(reader, listType);
I need to use a big file that contains String,String pairs and because I want to ship it with a JAR, I opted to include a serialized and gzipped version in the resource folder of the application. This is how I created the serialization:
ObjectOutputStream out = new ObjectOutputStream(
new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream(OUT_FILE_PATH, false))));
out.writeObject(map);
out.close();
I chose to use a HashMap<String,String>, the resulting file is 60MB and the map contains about 4 million entries.
Now when I need the map and I deserialize it using:
final InputStream in = FileUtils.getResource("map.ser.gz");
final ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new GZIPInputStream(in)));
map = (Map<String, String>) ois.readObject();
ois.close();
this takes about 10~15 seconds. Is there a better way to store such a big map in a JAR? I ask because I also use the Stanford CoreNLP library which uses big model files itself but seems to perform better in that regard. I tried to locate the code where the model files are read but gave up.
Your problem is you zipped the data. Store it plain text.
The performance hit is most probably in unzipping the stream. Jars are already zipped, so there's no space saving storing the file zipped.
Basically:
Store the file in plain text
Use Files.lines(Paths.get("myfilenane.txt")) to stream the lines
Consume each line with minimal code
Something like this, assuming data is in form key=value (like a Properties file):
Map<String, String> map = new HashMap<>();
Files.lines(Paths.get("myfilenane.txt"))
.map(s -> s.split("="))
.forEach(a -> map.put(a[0], a[1]));
Disclaimer: Code may not compile or work as it was thumbed in on my phone (but there's a reasonable chance it will work)
What you can do is to apply a technique coming from the book Java Performance: The definitive guide from Scott Oaks which actually stores the zipped content of the object into a byte array so for this we need a wrapper class that I call here MapHolder:
public class MapHolder implements Serializable {
// This will contain the zipped content of my map
private byte[] content;
// My actual map defined as transient as I don't want to serialize its
// content but its zipped content
private transient Map<String, String> map;
public MapHolder(Map<String, String> map) {
this.map = map;
}
private void writeObject(ObjectOutputStream out) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (GZIPOutputStream zip = new GZIPOutputStream(baos);
ObjectOutputStream oos = new ObjectOutputStream(
new BufferedOutputStream(zip))) {
oos.writeObject(map);
}
this.content = baos.toByteArray();
out.defaultWriteObject();
// Clear the temporary field content
this.content = null;
}
private void readObject(ObjectInputStream in) throws IOException,
ClassNotFoundException {
in.defaultReadObject();
try (ByteArrayInputStream bais = new ByteArrayInputStream(content);
GZIPInputStream zip = new GZIPInputStream(bais);
ObjectInputStream ois = new ObjectInputStream(
new BufferedInputStream(zip))) {
this.map = (Map<String, String>) ois.readObject();
// Clean the temporary field content
this.content = null;
}
}
public Map<String, String> getMap() {
return this.map;
}
}
Your code will then simply be:
final ByteArrayInputStream in = new ByteArrayInputStream(
Files.readAllBytes(Paths.get("/tmp/map.ser"))
);
final ObjectInputStream ois = new ObjectInputStream(in);
MapHolder holder = (MapHolder) ois.readObject();
map = holder.getMap();
ois.close();
As you may have noticed, you don't zip anymore the content it is zipped internally while serializing the MapHolder instance.
You could consider one of many fast serialization libraries:
protobuf (https://github.com/google/protobuf)
flat buffers (https://google.github.io/flatbuffers/)
cap'n proto (https://capnproto.org)
I wanted to save an ArrayList to SharedPreferences so I need to turn it into a string and back, this is what I am doing:
// Save to shared preferences
SharedPreferences sharedPref = this.getPreferences(Activity.MODE_PRIVATE);
SharedPreferences.Editor editor = this.getPreferences(Activity.MODE_PRIVATE).edit();
editor.putString("myAppsArr", myAppsArr.toString());
editor.commit();
I can retrieve it with String arrayString = sharedPref.getString("yourKey", null); but I don't know how to convert arrayString back into an ArrayList. How can it be done?
My array looks something like:
[item1,item2,item3]
You have 2 choices :
Manually parse the string and recreate the arraylist. This would be pretty tedious.
Use a JSON library like Google's Gson library to store and retrieve objects as JSON strings. This is a lightweight library, well regarded and popular. It would be an ideal solution in your case with minimal work required. e.g.,
// How to store JSON string
Gson gson = new Gson();
// This can be any object. Does not have to be an arraylist.
String json = gson.toJson(myAppsArr);
// How to retrieve your Java object back from the string
Gson gson = new Gson();
DataObject obj = gson.fromJson(arrayString, ArrayList.class);
Try this
ArrayList<String> array = Arrays.asList(arrayString.split(","))
This will work if comma is used as separator and none of the items have it.
The page http://mjiayou.com/2015/07/22/exception-gson-internal-cannot-be-cast-to/ contains the following:
Type type = new TypeToken<List<T>>(){}.getType();
List<T> list = gson.fromJson(jsonString, type)
perhaps it will be helpful.
//arraylist convert into String using Gson
Gson gson = new Gson();
String data = gson.toJson(myArrayList);
Log.e(TAG, "json:" + gson);
//String to ArrayList
Gson gson = new Gson();
arrayList=gson.fromJson(data, new TypeToken<List<Friends>>()
{}.getType());
I ended up using:
ArrayList<String> appList = new ArrayList<String>(Arrays.asList(appsString.split("\\s*,\\s*")));
This doesn't work for all array types though. This option differs from:
ArrayList<String> array = Arrays.asList(arrayString.split(","));
on that the second option creates an inmutable array.
Update to Dhruv Gairola's answer for Kotlin
val gson = Gson();
val jsonString = gson.toJson(arrayList)
i need to access the yaml file data into the java file.
i used the YamlReader class and now the yaml file is loaded into the java class object.
now all the information is in object and i want to extract it from this object.How can i do this .
Can any one help me please i am stuck with this problem.
You can read into a Map:
YamlReader reader = new YamlReader(new FileReader("contact.yml"));
Object object = reader.read();
System.out.println(object);
Map map = (Map)object;
System.out.println(map.get("address"));
Source: http://code.google.com/p/yamlbeans/
Yaml yaml = new Yaml();
String document = "\n- Hesperiidae\n- Papilionidae\n- Apatelodidae\n- Epiplemidae";
List<String> list = (List<String>) yaml.load(document);
System.out.println(list);
Using snakeyaml, the code below didn't work for me. When the yaml object returned my object, it returned a LinkedHashMap type. So I cast my returned object into a LinkedHashMap.
public class YamlConfig {
Yaml yaml = new Yaml();
String path = "blah blah";
InputStream input = new FileInputStream(new File(this.path));
LinkedHashMap<String,String> map;
#SuppressWarnings("unchecked")
private void loadHashMap() throws IOException {
Object data = yaml.load(input);// load the yaml document into a java object
this.map = (LinkedHashMap<String,String>)data;
System.out.println(map.entrySet()); //use this to look at your hashmap keys
System.out.println(map);//see the entire map
}
I have the following HashMap:
HashMap<String,Object> fileObj = new HashMap<String,Object>();
ArrayList<String> cols = new ArrayList<String>();
cols.add("a");
cols.add("b");
cols.add("c");
fileObj.put("mylist",cols);
I write it to a file as follows:
File file = new File("temp");
FileOutputStream f = new FileOutputStream(file);
ObjectOutputStream s = new ObjectOutputStream(f);
s.writeObject(fileObj);
s.flush();
Now I want to read this file back to a HashMap where the Object is an ArrayList.
If i simply do:
File file = new File("temp");
FileInputStream f = new FileInputStream(file);
ObjectInputStream s = new ObjectInputStream(f);
fileObj = (HashMap<String,Object>)s.readObject();
s.close();
This does not give me the object in the format that I saved it in.
It returns a table with 15 null elements and the < mylist,[a,b,c] > pair at the 3rd element. I want it to return only one element with the values I had provided to it in the first place.
//How can I read the same object back into a HashMap ?
OK So based on Cem's note: This is what seems to be the correct explanation:
ObjectOutputStream serializes the objects (HashMap in this case) in whatever format that ObjectInputStream will understand to deserialize and does so generically for any Serializable object.
If you want it to serialize in the format that you desire you should write your own serializer/deserializer.
In my case: I simply iterate through each of those elements in the HashMap when I read the Object back from the file and get the data and do whatever I want with it. (it enters the loop only at the point where there is data).
Thanks,
You appear to be confusing the internal resprentation of a HashMap with how the HashMap behaves. The collections are the same. Here is a simple test to prove it to you.
public static void main(String... args)
throws IOException, ClassNotFoundException {
HashMap<String, Object> fileObj = new HashMap<String, Object>();
ArrayList<String> cols = new ArrayList<String>();
cols.add("a");
cols.add("b");
cols.add("c");
fileObj.put("mylist", cols);
{
File file = new File("temp");
FileOutputStream f = new FileOutputStream(file);
ObjectOutputStream s = new ObjectOutputStream(f);
s.writeObject(fileObj);
s.close();
}
File file = new File("temp");
FileInputStream f = new FileInputStream(file);
ObjectInputStream s = new ObjectInputStream(f);
HashMap<String, Object> fileObj2 = (HashMap<String, Object>) s.readObject();
s.close();
Assert.assertEquals(fileObj.hashCode(), fileObj2.hashCode());
Assert.assertEquals(fileObj.toString(), fileObj2.toString());
Assert.assertTrue(fileObj.equals(fileObj2));
}
I believe you´re making a common mistake. You forgot to close the stream after using it!
File file = new File("temp");
FileOutputStream f = new FileOutputStream(file);
ObjectOutputStream s = new ObjectOutputStream(f);
s.writeObject(fileObj);
s.close();
you can also use JSON file to read and write MAP object.
To write map object into JSON file
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> map = new HashMap<String, Object>();
map.put("name", "Suson");
map.put("age", 26);
// write JSON to a file
mapper.writeValue(new File("c:\\myData.json"), map);
To read map object from JSON file
ObjectMapper mapper = new ObjectMapper();
// read JSON from a file
Map<String, Object> map = mapper.readValue(
new File("c:\\myData.json"),
new TypeReference<Map<String, Object>>() {
});
System.out.println(map.get("name"));
System.out.println(map.get("age"));
and import ObjectMapper from com.fasterxml.jackson and put code in try catch block
Your first line:
HashMap<String,Object> fileObj = new HashMap<String,Object>();
gave me pause, as the values are not guaranteed to be Serializable and thus may not be written out correctly. You should really define the object as a HashMap<String, Serializable> (or if you prefer, simpy Map<String, Serializable>).
I would also consider serializing the Map in a simple text format such as JSON since you are doing a simple String -> List<String> mapping.
I believe you're getting what you're saving. Have you inspected the map before you save it? In HashMap:
/**
* The default initial capacity - MUST be a power of two.
*/
static final int DEFAULT_INITIAL_CAPACITY = 16;
e.g. the default HashMap will start off with 16 nulls. You use one of the buckets, so you only have 15 nulls left when you save, which is what you get when you load.
Try inspecting fileObj.keySet(), .entrySet() or .values() to see what you expect.
HashMaps are designed to be fast while trading off memory. See Wikipedia's Hash table entry for more details.
Same data if you want to write to a text file
public void writeToFile(Map<String, List<String>> failureMessage){
if(file!=null){
try{
BufferedWriter writer=new BufferedWriter(new FileWriter(file, true));
for (Map.Entry<String, List<String>> map : failureMessage.entrySet()) {
writer.write(map.getKey()+"\n");
for(String message:map.getValue()){
writer.write(message+"\n");
}
writer.write("\n");
}
writer.close();
}catch (Exception e){
System.out.println("Unable to write to file: "+file.getPath());
e.printStackTrace();
}
}
}