【问题标题】:Java, convert Byte Array to HashMap or JSON stringJava,将字节数组转换为 HashMap 或 JSON 字符串
【发布时间】:2021-04-14 08:00:46
【问题描述】:

我正在制作一个 Android 应用程序来远程管理 Unix 计算机。该应用程序还允许您查看实时 PC 统计数据(CPU 温度、CPU 负载等)。在 PC 上有一个 Python 服务器,它通过套接字将 JSON 字符串作为字节数组发送到包含 PC 统计信息的应用程序,如下所示:

[123, 45, 67, 90, ...]

这是字节数组的内容(我是用网站解码的):

{
    "author": "Anton",
    "type": "server info",
    "date": "08/01/2021",
    "content": "",
    "opt": {
        "cpu": {
            "freq": [3866.041875, 1600.0, 3900.0],
            "usage": [0.0, 0.0, 1.0, 2.0, 1.0, 1.0, 0.0, 2.0],
            "load": [0.5, 0.63, 0.61]
        },
        "memory": {
            "ram": [15.54, 12.01, 22.7, 2.85, 9.67]
        },
        "disks": {
            "ssd": [219.1, 13.0, 194.9, 6.3],
            "hdd": [0.0, 0.0, 0, 100.0]
        },
        "temps": {
            "core-0": [32.0, 85.0, 105.0],
            "core-1": [36.0, 85.0, 105.0],
            "core-2": [37.0, 85.0, 105.0],
            "core-3": [38.0, 85.0, 105.0]
        }
    },
    "attached": null
}

如何将字节数组转换为HashMap或JSON字符串等结构,以便检索PC统计信息,然后通过ProgressiveBars在App中查看?

【问题讨论】:

  • 您是否在问如何将字节数组解码为您已经提供的 JSON 字符串?或者您是在询问将您提供的 JSON 字符串(从网站解码)转换为像 HashMap 这样的 Java 结构?
  • 我应该将字节数组转换成一个 HashMap,或者在任何情况下,一个允许我检索它的每一个数据的结构。
  • @DanieleMonaldi“JSON 字符串作为字节数组”不清楚。 [123, 45, 67, 90, ...] 是在逻辑上表示数据(即第一个字节的值是 123,依此类推),还是在物理上表示数据(即,字面意思是 [123 , ,, ...通过你的网络)?
  • @fluffy 服务器向我发送 JSON 字符串,就像我以字节数组的形式发布的字符串一样,例如 123 代表字符“{”
  • @DanieleMonaldi 我有一个使用 Gson 解码它的想法,但让我先问你三个问题。 1) 123456790 分别代表 ASCII/UTF-8 字符 {-CZ(格式错误但异常的 JSON):它们在结构上与 JSON 不同,但为什么呢? 2) 当我对你的 JSON 进行漂亮的格式化时,我发现它是非法的:是你的服务器发送给你的东西还是你在发布它时有一些拼写错误? 3) 你的服务器不应该发送一个现成的 JSON,而不是发送一个字节数组编码的 JSON,不一定与 JSON 兼容吗?

标签: java android arrays json hashmap


【解决方案1】:

与此同时,虽然您的服务器代码尚未修复,但出于“教育”目的,我可以提供一个示例,让字节编码的响应适应您可以解析的内容,以避免将来出现不良做法(请不要'不要执行以下操作)。

解决您的问题的想法是调整传入的有效负载(字节数组编码的文本)到可以作为 JSON 使用的字节/字符流。

使用 org.json 可能这样实现(但是,我不确定我是否正确实现了它):

public final class Decoding {

    private Decoding() {
    }

    public static Reader of(final Reader reader) {
        final JSONTokener jsonTokener = new JSONTokener(reader);
        return new Reader() {
            private boolean beginToProcess = true;
            private boolean endToProcess = true;

            @Override
            public int read(@Nonnull final char[] buffer, final int offset, final int length)
                    throws IOException {
                if ( beginToProcess ) {
                    final char ch = jsonTokener.nextClean();
                    if ( ch != '[' ) {
                        throw new IOException("Not an array begin: " + ch);
                    }
                    beginToProcess = false;
                }
                if ( !jsonTokener.more() ) {
                    if ( endToProcess ) {
                        final char ch = jsonTokener.nextClean();
                        if ( ch != '\u0000' ) {
                            throw new IOException("Not an array or document end: " + ch);
                        }
                        endToProcess = false;
                    }
                    return -1;
                }
                final char b = (char) (int) jsonTokener.nextValue();
                if ( jsonTokener.more() ) {
                    final char ch = jsonTokener.nextClean();
                    switch ( ch ) {
                    case ',':
                    case ']':
                        // do nothing
                        break;
                    default:
                        throw new IOException("Not an array delimiter: " + ch);
                    }
                }
                buffer[offset] = b;
                return 1;
            }

            @Override
            public void close()
                    throws IOException {
                reader.close();
            }
        };
    }
    ...

或以 Gson 为例:

    ...
    public static Reader of(final JsonReader jsonReader) {
        return new Reader() {
            private boolean beginToProcess = true;
            private boolean endToProcess = true;

            @Override
            public int read(@Nonnull final char[] buffer, final int offset, final int length)
                    throws IOException {
                if ( beginToProcess ) {
                    jsonReader.beginArray();
                    beginToProcess = false;
                }
                if ( !jsonReader.hasNext() ) {
                    if ( endToProcess ) {
                        jsonReader.endArray();
                        endToProcess = false;
                    }
                    return -1;
                }
                final int b = jsonReader.nextInt();
                buffer[offset] = (char) b;
                return 1;
            }

            @Override
            public void close()
                    throws IOException {
                jsonReader.close();
            }
        };
    }

}

这两种解码器都不是最理想的,不能提供最佳性能,但我希望你的服务器修复后就不需要它了。现在您可以解码输入阅读器并将它们转换为有效的 JSON 文档(在 JUnit 5 测试中):

public final class DecodingTest {

    @Test
    public void test()
            throws IOException {
        final String payload = "[123,34,97,117,116,104,111,114,34,58,34,65,110,116,111,110,34,44,34,116,121,112,101,34,58,34,115,101,114,118,101,114,32,105,110,102,111,34,44,34,100,97,116,101,34,58,34,48,56,47,48,49,47,50,48,50,49,34,44,34,99,111,110,116,101,110,116,34,58,34,34,44,34,111,112,116,34,58,123,34,99,112,117,34,58,123,34,102,114,101,113,34,58,91,51,56,54,54,46,48,52,49,56,55,53,44,49,54,48,48,44,51,57,48,48,93,44,34,117,115,97,103,101,34,58,91,48,44,48,44,49,44,50,44,49,44,49,44,48,44,50,93,44,34,108,111,97,100,34,58,91,48,46,53,44,48,46,54,51,44,48,46,54,49,93,125,44,34,109,101,109,111,114,121,34,58,123,34,114,97,109,34,58,91,49,53,46,53,52,44,49,50,46,48,49,44,50,50,46,55,44,50,46,56,53,44,57,46,54,55,93,125,44,34,100,105,115,107,115,34,58,123,34,115,115,100,34,58,91,50,49,57,46,49,44,49,51,44,49,57,52,46,57,44,54,46,51,93,44,34,104,100,100,34,58,91,48,44,48,44,48,44,49,48,48,93,125,44,34,116,101,109,112,115,34,58,123,34,99,111,114,101,45,48,34,58,91,51,50,44,56,53,44,49,48,53,93,44,34,99,111,114,101,45,49,34,58,91,51,54,44,56,53,44,49,48,53,93,44,34,99,111,114,101,45,50,34,58,91,51,55,44,56,53,44,49,48,53,93,44,34,99,111,114,101,45,51,34,58,91,51,56,44,56,53,44,49,48,53,93,125,125,44,34,97,116,116,97,99,104,101,100,34,58,110,117,108,108,125]";
        final String expected = "{\"author\":\"Anton\",\"type\":\"server info\",\"date\":\"08/01/2021\",\"content\":\"\",\"opt\":{\"cpu\":{\"freq\":[3866.041875,1600,3900],\"usage\":[0,0,1,2,1,1,0,2],\"load\":[0.5,0.63,0.61]},\"memory\":{\"ram\":[15.54,12.01,22.7,2.85,9.67]},\"disks\":{\"ssd\":[219.1,13,194.9,6.3],\"hdd\":[0,0,0,100]},\"temps\":{\"core-0\":[32,85,105],\"core-1\":[36,85,105],\"core-2\":[37,85,105],\"core-3\":[38,85,105]}},\"attached\":null}";
        try ( final Reader reader = Decoding.of(new StringReader(payload));
                final Writer writer = new StringWriter() ) {
            CharStreams.copy(reader, writer);
            Assertions.assertEquals(expected, writer.toString());
        }
        try ( final Reader reader = Decoding.of(new JsonReader(new StringReader(payload)));
                final Writer writer = new StringWriter() ) {
            CharStreams.copy(reader, writer);
            Assertions.assertEquals(expected, writer.toString());
        }
    }

}

请注意,CharStreams.copy 为简洁起见取自 Google Guava。

现在可以将阅读器作为常规 JSON 文档被库、org.json、Gson、Jackson、Moshi 或其他任何东西使用。

【讨论】:

    【解决方案2】:

    您应该能够使用来自 Jackson 的 ObjectMapper 或任何其他 JSON 解析器/序列化器来实现此目的。使用 ObjectMapper 的一种选择是将字符串直接序列化为哈希映射,如下所示:

    byte src[] = getBytesFromServer();
    ObjectMapper om = new ObjectMapper();
    TypeReference<Map<String,Object>> tr = new TypeReference<Map<String,Object>> {};
    Map<String,Object> val = om.readValue(src,tr);
    

    这有一些变体应该对您有所帮助。您也可以使用其他 JSON 库实现相同的功能,例如 GSon

    【讨论】:

      猜你喜欢
      • 2011-02-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-06
      • 2013-12-19
      • 2011-07-26
      • 1970-01-01
      相关资源
      最近更新 更多