Reputation: 874
I am basically trying to write multiple (12, specifically) HashMap dictionaries to a local file and then retrieve them. So far I manage to do one however when I am trying to do more than one, i basically can not make it work. So any help to do this is appreciated. Here's my code so far:
private HashMap<String, List<String>> loadDict() {
int month = Functions.getMonth();
//load back in
FileInputStream fis;
try {
fis = new FileInputStream(statsFile);
ObjectInputStream ois = new ObjectInputStream(fis);
for (int i = 0; i < 13; i++) {
//itemsDict = (HashMap) ois.readObject();
Object whatisThis = (Object) ois.readObject();
dictionaries.add(whatisThis);
}
ois.close();
fis.close();
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (ClassNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
itemsDict = (HashMap) dictionaries.get(month);
System.out.println(itemsDict.get("cake"));
return itemsDict;
}
private void setupDictionaries() {
HashMap<String, List<String>> dictionary = new HashMap<String,List<String>>();
FileOutputStream fos;
try {
fos = new FileOutputStream(statsFile);
ObjectOutputStream oos = new ObjectOutputStream(fos);
for (int i = 0; i < 13; i++) {
oos.writeObject(dictionary);
}
oos.close();
fos.close();
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void storeThis(String product, String price, String quantity, String date, List<List<String>> myContent) {//after set, replace dictionary in dictionaries array
dictionaries.set(Functions.getMonth(), itemsDict);
//save the dictionary to the overall statistics file
FileOutputStream fos;
try {
fos = new FileOutputStream(statsFile);
ObjectOutputStream oos = new ObjectOutputStream(fos);
for (int i = 0; i < 13; i++) {
oos.writeObject(dictionaries.get(i));
}
//oos.writeObject(itemsDict);
oos.close();
fos.close();
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
A bit of clarification: setupDictionaries is only called on the first run (to setup the file), otherwise loadDict() is called on runtime, to load all the dictionaries into an arraylist. From the arraylist, the correct object (hashmap) should be chosen and then cased to itemsDict as hashmap. storeThis() is called when a button is pressed, however I cut down the code to only relevant bits.
So I am trying to implement the JSON you have suggested, so far I've got:
private void setupDictionaries() {
ObjectMapper mapper = new ObjectMapper();
ArrayNode arrayNode = mapper.createArrayNode();
JsonNode rootNode = mapper.createObjectNode();
ArrayList<String> myThing = new ArrayList<String>();
myThing.add("hi");
myThing.add(".");
itemsDict.put("cake", myThing);
JsonNode childNode1 = mapper.valueToTree(itemsDict);
((ObjectNode) rootNode).set("Jan", childNode1);
JsonNode childNode2 = mapper.createObjectNode();
((ObjectNode) rootNode).set("obj2", childNode2);
JsonNode childNode3 = mapper.createObjectNode();
((ObjectNode) rootNode).set("obj3", childNode3);
String jsonString;
try {
jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(rootNode);
System.out.println(jsonString);
ObjectWriter writer = mapper.writer(new DefaultPrettyPrinter());
writer.writeValue(new File(statsFile), jsonString);
} catch (JsonProcessingException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Question, how would I be able to load this back? (only everything underneath Jan for example, to a hashmap)
private HashMap<String, List<String>> loadDict() {
ObjectMapper mapper = new ObjectMapper();
try {
HashMap<String, ArrayList<String>> map = mapper.readValue(new File(statsFile), new TypeReference<HashMap<String, ArrayList<String>>>() {});
System.out.println(map.get("Jan"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
With this code I would be able to load it, however I get this exception (because I have multiple hashmaps within the Json):
JsonMappingException: Can not construct instance of java.util.HashMap: no String-argument constructor/factory method to deserialize from String value
(I don't know how to put exceptions here)
My JSON:
"{\r\n \"Jan\" : {\r\n \"cake\" : [ \"hi\", \".\" ]\r\n },\r\n \"obj2\" : { },\r\n \"obj3\" : { }\r\n}"
So how would I be able to only load a specific month into a hashmap?
Upvotes: 1
Views: 830
Reputation: 2608
When you've got multiple independently growing lists or equivalent and are trying to handle storing within a single file, the question is how would you want to handle overlap.
What would also matter is how frequently you write versus how frequently the data is read. If its mostly reads and long pauses are fine, then go for using json format (every time an edit is made then you have to re-write the whole json and the reads will have to wait until the operation is complete).
However if read and write would be approximately equal in measure then I think you'll need to consider splitting up the data into sequential sections - similar to what a database might do it.
===============================================================================
For example :
meta-data + 1*1024 bytes of 01st map
meta-data + 1*1024 bytes of 02nd map
meta-data + 1*1024 bytes of 03rd map
..
meta-data + 1*1024 bytes of 12th map
meta-data + 2*1024 bytes of 01st map
meta-data + 2*1024 bytes of 02nd map
..
meta-data + 2*1024 bytes of 12th map
meta-data + 3*1024 bytes of 01st map
...
and so on..
The meta-data will tell you whether to continue to the next section for any given map's data.
===============================================================================
You would also have to consider things like whether you are using hard-disk (sequential access) or SSD (random-access) and then decide which approach you want to go with.
Upvotes: 0
Reputation: 30087
I would definitely use Json format, consider that this format (which is plain text) give you the freedom to edit the file with an editor.
I'll suggest to use Jackson library.
You have just to create an ObjectMapper
and use it to serialise and deserialise the json. Reading the documentation I see you can also read and write json files.
ObjectMapper objectMapper = new ObjectMapper();
For example this line would convert a Json String into a Map
;
Map<String, Object> map = objectMapper.readValue(json, new TypeReference<Map<String, Object>>() {});
And you can convert a map into a Json even easier:
objectMapper.writeValueAsString(json)
The rest of your problem remain read and write the files.
Upvotes: 1