序列化键值对的HashMap并将其转换为Java中的格式化字符串

时间:2019-01-09 21:25:13

标签: java string serialization hashmap deserialization

我将键值对的哈希映射声明为

HashMap<String, String> map = new HashMap<>();
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");

我正在使用一种方法来序列化此哈希图,并使用以下代码将其转换为字符串:

public static String serializeMetadata(HashMap<String, String> metadata) throws IOException {
    try(ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
        ObjectOutputStream oos = new ObjectOutputStream(baos)) {
        oos.writeObject(metadata);
        return baos.toString();
    }
}

当我调用serializeMetadata方法并将哈希图作为输入传递时,我期望映射状态由ObjectOutputStream(oos)流传输并将字节数组存储在ByteArrayOutputStream(baos)中。当使用baos调用toString()时,我期望输出

  

“ {key1 = value1,key2 = value2,key3 = value3}”

当我们将哈希图转换为字符串时,输出与之相同。相反,我得到了一些不可读的格式化字符串,例如

  

�sr�java.util.HashMap���������   loadFactorI。thresholdxp?@����������t.key1t.value1t.key2t.value2t.key3t.value3x

我了解,如果我对baos进行反序列化,则会再次获得一个哈希图,如果执行toString(),则会获得所需的格式。

当序列化哈希图转换为字符串时,我需要一个格式化的字符串,所以, 1.我可以编写一个单元测试并声明一个字符串的哈希表 2.将该字符串(包含所有格式化的键和值)保留在DB中,以供将来进行数据分析。 3.我可以在应用程序中从数据库调用该字符串,然后将其反序列化为哈希图,然后继续使用现有状态。

我不需要JSON字符串。想象一下,哈希表的所有键值对都存储在DB的单个字段中。我找不到正确的解决方案,因此,如果有重复的链接,请在注释中注明。任何帮助表示赞赏。谢谢!

2 个答案:

答案 0 :(得分:1)

ObjectOutputStream outputs in a binary format and need an ObjectInputStream to read. If you go via String in between as well it will probably not even work.

The easiest solution is probably to use existing classes such as java.util.Properties which inherits from Hashtable (and implements Map as well) and can take all entries from another Map or act as one. Properties can easily be stored to disk via load/store methods (both line based strings key=value and xml format).

To save to a text readable file:

Properties<String, String> props = new Properties<>();
props.putAll(map);
props.store(...);

To read them back again:

Properties<String, String> props = new Properties<>();
props.load(...);

map.putAll(props);
//or just use the props object as your Map as it implements the Map interface, 
//so instead just do this:
Map<String, String> map = props;

https://docs.oracle.com/javase/8/docs/api/java/util/Properties.html

答案 1 :(得分:0)

首先,您说不需要JSON字符串。但是根据您打算将其用作什么,JSON字符串就可以正常工作。

但是这里有一个快速而肮脏的建议,将这些值序列化为分隔符分隔的字符串:

  1. 将地图复制到TreeMap,以便将键按一致的顺序排序。

  2. values()上使用TreeMap来获取值作为列表。

  3. 将列表序列化为字符串;例如使用StringJoiner和您首选的定界符。

问题:

  1. 如果地图的键集不一致,则渲染将不明确。

  2. 如果值类型的toString()方法不合适,则可能会导致模棱两可的渲染;例如如果您选择的字段定界符也出现在toString()输出中。

  3. 如果地图的键名随时间变化,则可能会遇到麻烦。

  4. 如果不知道键名应该是什么,就无法重建地图。

使用JSON可以避免所有这些问题:提示!如果您可以使用CSV库一次编码一行,则可以解决1.和2.。


另一种替代方法是使用ObjectOutputStream将映射序列化为ByteArrayOutputStream,然后使用base64编码对捕获的字节进行编码。结果可以存储在数据库中,并在以后用于重建HashMap

缺点是base64编码是不透明的,可能会比JSON版本占用更多空间。


您谈到了当前版本:

  

...我知道,如果我反序列化BAOS,则会得到一个哈希图。

是的。但是,如果将BAOS内容“解码”为String,则可能会遇到问题,具体取决于您选择的字符集。您的“无法读取的字符串”是发生这种情况的典型示例,这些“。”字符可能表示无法正确解码且不会重新编码的字符。