我有一个HashMap<Person,List<Pet>
需要保存到文本文件中。
我写了这个方法:
public void writeToNotepad(){
try(PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(textFileName + ".txt")))) {
if (map.size() < 1)
return;
Set<Map.Entry<Person, List<Pet>>> mapEntry = map.entrySet();
for (Map.Entry<Person, List<Pet>> mapEn :
mapEntry) {
Person p = mapEn.getKey();
Iterator<Pet> iter = mapEn.getValue().iterator();
while (iter.hasNext()){
Pet pet = iter.next();
pw.println(p.getName() + " " + p .getAge() + " " + p.getSex()
+ " " + pet.getName()
+ " " + pet.getType()
+ " " + pet.getAge());
}
}
pw.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
但它多次保存地图密钥(我认为这是因为迭代器) 这是输出:
JOHN 10 MALE Dog 3
AISEC 12 MALE Loo Cat 12
AISEC 12 MALE Kitty Cat 4
如你所见,Aisec重复2次。 我需要从这个文本文件中读取以填充地图。 这是写入文件的好方法,还是我可以更好地使用?
答案 0 :(得分:1)
...如果名称包含两个单词之间有空白,该怎么办?
为什么需要为序列化和反序列化创建自己的格式?为什么不使用像json这样的行业标准,在那里你可以利用任何可以进行序列化和反序列化的库。你需要我告诉你怎么样?
修改强>
好的,事实证明使用json并不像我最初想的那么简单。不要误解我的意思,它仍然比自定义格式更好,因为它是防错的,并支持像我上面描述的边缘情况。
json的障碍是每个对象和属性的关键必须是String。因此,当密钥是用户定义的类型(如您的情况下为Person
)时,它没有正确序列化 - 在序列化到json之前需要一个过渡数据结构。
所以这就是我所做的:对于你字典中的每个条目,我创建了一个包含两个条目的地图:一个带有Person对象的json String表示的“person”条目,以及一个带有json的“pets”条目宠物列表的字符串表示。因此,要序列化的最终字符串实际上是List
的{{1}}。
给你一个想法:每个地图条目看起来像json:
Map
反序列化只是反向操作。
我使用Jackson库作为json解析器和编写器
这是序列化方法。它返回一个{
"person":{"name":"AISEC","age":12,"sex":"MALE"},
"pets":[
{"name":"Loo","age":12,"type":"Cat"},
{"name":"Kitty","age":4,"type":"Cat"}
]
}
,可以写入文件:
String
反序列化方法接受String(文件的整个内容):
public String dictToJson(Map<Person, List<Pet>> map) throws IOException
{
ObjectMapper mapper = new ObjectMapper();
// serialized dictionary is list of maps
List<Map<String, String>> jsonDictionary = new ArrayList<>();
for (Map.Entry<Person, List<Pet>> mapEntry : map.entrySet()) {
// each map entry becomes its own map instance with two entries
Map<String, String> jsonEntry = new HashMap<>();
// write person key as "person" with json string represetation of person object
jsonEntry.put("person", mapper.writeValueAsString(mapEntry.getKey()));
// write pets value as "pets" key with json string represetation of pets list
jsonEntry.put("pets", mapper.writeValueAsString(mapEntry.getValue()));
jsonDictionary.add(jsonEntry);
}
return mapper.writeValueAsString(jsonDictionary);
}
用法和测试方法:
public Map<Person, List<Pet>> jsonToDict(String json) throws IOException
{
Map<Person, List<Pet>> map = new HashMap<>();
ObjectMapper mapper = new ObjectMapper();
// read json String into list of maps
List<Map<String, String>> jsonDictionary =
mapper.readValue(json, new TypeReference<List<Map<String, Object>>>(){});
// each list item is a map with two entries
for (Map<String, String> jsonEntry : jsonDictionary) {
map.put(
mapper.readValue(jsonEntry.get("person"), Person.class),
mapper.readValue(jsonEntry.get("pets"), new TypeReference<List<Pet>>(){}));
}
return map;
}
答案 1 :(得分:0)
我忽略了读+写部分。
首先谈谈这件事:您实际需要的是人类可读 序列化数据的方式。有多种方法可以实现:A)您定义自己的文本格式B)您使用现有技术,如JSON或XML。
我的建议:学习如何使用在JSON字符串中转换数据的库;然后写那些;并使用JSON解析器读回它们。
关键部分是:无论你是什么,你都必须思考通过你在这里做的事情。 您必须为您的数据定义合理的格式;然后你必须编写代码来创建/解析该内容。
但是,在你问题的第二部分;出现的当前输出:
下面;在你的内循环中:
pw.println(p.getName() + " " + p .getAge() + " " + p.getSex()
+ " " + pet.getName()
+ " " + pet.getType()
+ " " + pet.getAge());
您正在进行println调用以打印所有信息。在内部循环中循环内部列表的条目。
你真的很惊讶在外环内运行的内循环会导致这个结果吗?!
所以,答案是:你必须退后一步。你把代码放下来打印
Owner NAME AGE pet1 details
Owner NAME AGE pet2 details
等等。您必须返工该代码;首先,您必须澄清所需的输出格式。例如,可能是:
Owner NAME AGE pet1 details | pet 2 details | and so forth
你可以通过创建一个像
这样的辅助方法来获得public String toString(List<Pet> pets) {
现在你只是迭代你的宠物主人;并为每位所有者打印所有者详细信息;然后你将这个方法用于宠物串。
除此之外:您可以查看覆盖
public String toString()
在你的人和你的宠物类上。换句话说:不要询问您的对象的详细信息,以便从中构建字符串。相反:告诉对象提供自己的字符串表示。
然后进行完整的打印输出将归结为:
foreach mapEn
System.out.println("Owner: " + mapEn.getKey().toString() + " pets: " + mapEn.getValue().toString());