如何从 Java HTTPResponse 解析 JSON?

Posted

技术标签:

【中文标题】如何从 Java HTTPResponse 解析 JSON?【英文标题】:How do I parse JSON from a Java HTTPResponse? 【发布时间】:2011-02-20 04:42:43 【问题描述】:

我有一个 HttpResponse 对象,用于我刚刚发出的 Web 请求。响应是 JSON 格式,所以我需要解析它。我可以用一种荒谬的复杂方式来做到这一点,但似乎必须有更好的方法。

这真的是我能做到的最好的吗?

    HttpResponse response; // some response object
    Reader in = new BufferedReader(
        new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
    StringBuilder builder= new StringBuilder();
    char[] buf = new char[1000];
    int l = 0;
    while (l >= 0) 
        builder.append(buf, 0, l);
        l = in.read(buf);
    
    JSONTokener tokener = new JSONTokener( builder.toString() );
    JSONArray finalResult = new JSONArray( tokener );

如果这有什么不同的话,我使用的是 android

【问题讨论】:

【参考方案1】:

两件事可以更有效地完成:

    使用StringBuilder 而不是StringBuffer,因为它是更快更小的兄弟。 使用BufferedReader#readLine() 逐行读取,而不是逐字符读取。

HttpResponse response; // some response object
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
StringBuilder builder = new StringBuilder();
for (String line = null; (line = reader.readLine()) != null;) 
    builder.append(line).append("\n");

JSONTokener tokener = new JSONTokener(builder.toString());
JSONArray finalResult = new JSONArray(tokener);

如果 JSON 实际上是单行,那么你也可以去掉循环和构建器。

HttpResponse response; // some response object
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
String json = reader.readLine();
JSONTokener tokener = new JSONTokener(json);
JSONArray finalResult = new JSONArray(tokener);

【讨论】:

问题中的代码不会一次从流中读取 1000 个字节吗?显然,这取决于输出的平均行大小,但这很可能比每行一个批次少。 不,正如方法名称已经暗示的那样,BufferedReader#readLine() 逐行读取流。 IE。它在换行符上拆分流。尝试一下,亲自体验一下。 对。这就是我的观点。如果一行平均少于 1000 个字符,则使用 BufferedReader#readLine() 将涉及比 BufferedReader#read() 更多的循环次数。 (除非输出有很多短线,否则差异可能并不重要。) BufferedReader 在内部已经缓冲了 8KB。毕竟,这很可能是微优化,无论哪种方式都足够好,我更喜欢更易读的代码。您使用的习语是典型的字节流,而不是字符流。 PS:您为什么编辑问题以将StringBuffer 替换为StringBuilder?现在我的建议对于第一次阅读这个问题的人来说意义不大:) 我只是更改了变量名。在问题的原始版本中,它是一个 StringBuilder,但我可以看到使用“缓冲区”这个名称可能会造成混淆。 :)【参考方案2】:

使用简单的 JSON,

http://code.google.com/p/json-simple/

占用空间小,无依赖,因此非常适合 Android。

你可以这样做,

Object obj=JSONValue.parse(buffer.tString());
JSONArray finalResult=(JSONArray)obj;

【讨论】:

这个比内置的org.json包有什么优势? 如果您熟悉 org.json 并且您的应用仅适用于 Android,它可能没有优势。否则,json-simple 使用起来更简单,JAR 也更小(14k 对 43k)。我们在任何地方都使用它,甚至在 Android 上也是如此。【参考方案3】:

可以使用Gson库进行解析

void getJson() throws IOException 
    HttpClient  httpClient = new DefaultHttpClient();
    HttpGet httpGet = new HttpGet("some url of json");
    HttpResponse httpResponse = httpClient.execute(httpGet);
    String response = EntityUtils.toString(httpResponse.getEntity());

    Gson gson = new Gson();
    MyClass myClassObj = gson.fromJson(response, MyClass.class);


这是从服务器获取的示例 json 文件


"id":5,
"name":"kitkat",
"version":"4.4"

这是我的课

class MyClass
int id;
String name;
String version;

参考this

【讨论】:

【参考方案4】:

Jackson 似乎支持直接从InputStream 解析一定数量的 JSON。我的理解是它在 Android 上运行并且相当快。另一方面,它是一个额外的 JAR,可以包含在您的应用中,从而增加下载量和闪存大小。

【讨论】:

【参考方案5】:

而不是做

Reader in = new BufferedReader(
    new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
StringBuilder builder= new StringBuilder();
char[] buf = new char[1000];
int l = 0;
while (l >= 0) 
    builder.append(buf, 0, l);
    l = in.read(buf);

JSONTokener tokener = new JSONTokener( builder.toString() );

你可以这样做:

JSONTokener tokener = new JSONTokener(
                           IOUtils.toString(response.getEntity().getContent()) );

IOUtils 来自公共 IO 库。

【讨论】:

【参考方案6】:

对于 Android,并使用 Apache 的 Commons IO Library for IOUtils

// connection is a HttpURLConnection
InputStream inputStream = connection.getInputStream()
ByteArrayOutputStream baos = new ByteArrayOutputStream();
IOUtils.copy(inputStream, baos);
JSONObject jsonObject = new JSONObject(baos.toString()); // JSONObject is part of Android library

【讨论】:

【参考方案7】:

没有必要自己做阅读器循环。 JsonTokener 内置了这个。例如

ttpResponse response; // some response object
BufferedReader reader = new BufferedReader(new    
JSONTokener tokener = new JSONTokener(reader);
JSONArray finalResult = new JSONArray(tokener);

【讨论】:

我找不到任何接受 BufferedReader 的 JSONTokener 构造函数,因此这个答案具有误导性。 没有构造函数接受 BufferedReader 但 Reader 和 BufferedReader 是 Reader 的子类。 --> org.json.JSONTokener(Reader reader) 这个构造函数似乎不是 Android 的一部分:developer.android.com/reference/org/json/JSONTokener.html 我是从 json.org 网站获得的,这似乎与 android 版本不同。

以上是关于如何从 Java HTTPResponse 解析 JSON?的主要内容,如果未能解决你的问题,请参考以下文章

解析 Android HttpResponse 缓存更新?

如何从 Apache HttpClient5 的 HttpResponse 中获取响应体?

从 org.apache.http.HttpResponse 获取 HTTP 代码

在Java中怎样得到一个HttpResponse对象

Django HttpResponse与JsonResponse

PC 上的 Android 与 Java:不同的 HttpResponse?