Сериализация HashMap пар ключ-значение и преобразование его в форматированную строку в Java - PullRequest
0 голосов
/ 10 января 2019

Я объявил хэш-карту пар ключ-значение как,

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

Я использую метод для сериализации этого hashmap и преобразования его в строку, используя следующий код:

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). когда toString () вызывается с baos, я ожидаю вывод

"{ключ1 = значение1, ключ2 = значение2, ключ3 = значение3}"

Точно такой же вид вывода, когда мы конвертируем хэш-карту в строку. Вместо этого я получаю нечитаемую отформатированную строку, например,

srjava.util.HashMap`F loadFactorI thresholdxp? @ t key1t value1t key2t value2t key3t value3x

Я понимаю, что если я десериализирую baos, я снова получаю хэш-карту, и если я делаю toString (), я получаю нужный мне формат.

Мне нужна отформатированная строка, когда сериализованный хэш-файл конвертируется в строку, поэтому 1. Я могу написать модульный тест и установить хэш-карту для строки 2. Сохраните эту строку (которая имеет все отформатированные ключи и значения) в БД для последующего анализа данных. 3. Я могу вызвать строку из БД в приложении и десериализовать ее обратно в хэш-карту и продолжить использовать существующие состояния.

Мне не нужна строка JSON. Представьте, что все пары ключ-значение в hashmap хранятся в одном поле БД. Я не смог найти правильного решения, поэтому, если есть дубликаты ссылок, пожалуйста, оставьте их в комментариях. Любая помощь приветствуется. Спасибо!

Ответы [ 2 ]

0 голосов
/ 10 января 2019

Прежде всего, вы говорите, что вам не нужна строка 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, у вас могут возникнуть проблемы, в зависимости от выбранной вами кодировки. Ваша «нечитаемая строка» является типичным примером того, что происходит, и эти символы « », вероятно, указывают символы, которые не могут быть правильно декодированы и не будут перекодированы.

0 голосов
/ 10 января 2019

ObjectOutputStream выводит в двоичном формате и нуждается в ObjectInputStream для чтения. Если вы пройдете через String между ними, это, вероятно, даже не будет работать.

Самым простым решением, вероятно, является использование существующих классов, таких как java.util.Properties, который наследуется от Hashtable (и реализует также Map) и может принимать все записи из другой Map или действовать как единое целое. Свойства могут быть легко сохранены на диск с помощью методов загрузки / хранения (обе строки: строковый ключ = значение и формат xml).

Чтобы сохранить текстовый файл для чтения:

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

Чтобы прочитать их снова:

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

...