将map <object,list <object =“”>写入文本文件java

时间:2016-12-21 10:03:40

标签: java dictionary serialization

我有一个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次。 我需要从这个文本文件中读取以填充地图。 这是写入文件的好方法,还是我可以更好地使用?

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解析器读回它们。

进一步阅读:writingparsing

关键部分是:无论你是什么,你都必须思考通过你在这里做的事情。 必须为您的数据定义合理的格式;然后你必须编写代码来创建/解析该内容。

但是,在你问题的第二部分;出现的当前输出:

下面;在你的内循环中:

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());