Как разобрать огромный файл JSON, не загружая его в память - PullRequest
0 голосов
/ 22 февраля 2019

У меня большой JSON-файл (2,5 МБ), содержащий около 80000 строк.

Это выглядит так:

{
  "a": 123,
  "b": 0.26,
  "c": [HUGE irrelevant object],
  "d": 32
}

Я хочу, чтобы целые значения хранились только для ключей a, b и d и игнорировать остальную часть JSON (то есть игнорировать все, что есть в значении c).

Я не могу изменить исходный JSON, поскольку он создается сторонней службой, который я загружаю со своего сервера.

Как мне это сделать, не загружая весь файл в память?

Я попытался использовать библиотеку gson и создал боб следующим образом.:

public class MyJsonBean {
  @SerializedName("a")
  @Expose
  public Integer a;

  @SerializedName("b")
  @Expose
  public Double b;

  @SerializedName("d")
  @Expose
  public Integer d;
}

но даже тогда, чтобы десериализовать его с помощью Gson, мне нужно сначала скачать + прочитать весь файл в памяти и передать его в виде строки в Gson?

File myFile = new File(<FILENAME>);
myFile.createNewFile();

URL url = new URL(<URL>);
OutputStream out = new BufferedOutputStream(new FileOutputStream(myFile));
URLConnection conn = url.openConnection();

HttpURLConnection httpConn = (HttpURLConnection) conn;

InputStream in = conn.getInputStream();
byte[] buffer = new byte[1024];

int numRead;
while ((numRead = in.read(buffer)) != -1) {
  out.write(buffer, 0, numRead);
}

FileInputStream fis = new FileInputStream(myFile);
byte[] data = new byte[(int) myFile.length()];
fis.read(data);
String str = new String(data, "UTF-8");

Gson gson = new Gson();
MyJsonBean response = gson.fromJson(str, MyJsonBean.class);

System.out.println("a: " + response.a + "" + response.b + "" + response.d);

Есть ли способ избежать загрузки всего файла и просто получить нужные мне значения?

Ответы [ 2 ]

0 голосов
/ 22 февраля 2019

Есть несколько превосходных библиотек для анализа больших файлов JSON с минимальными ресурсами.Одним из них является популярная библиотека GSON .Это дает тот же эффект синтаксического анализа файла, что и поток и объект.Он обрабатывает каждую запись по мере прохождения, затем отбрасывает поток, сохраняя низкое использование памяти.

Если вы заинтересованы в использовании подхода GSON, здесь есть отличное руководство. Подробное руководство

0 голосов
/ 22 февраля 2019

Вы обязательно должны проверить разные подходы и библиотеки.Если вы действительно позаботились о проверке производительности: Gson, Jackson и JsonPath библиотеки, чтобы сделать это, и выберите самую быструю.Определенно, вам нужно загрузить весь файл JSON на локальный диск, возможно, папку TMP и проанализировать его после этого.

Простое решение JsonPath может выглядеть следующим образом:

import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;

import java.io.File;

public class JsonPathApp {
    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        DocumentContext documentContext = JsonPath.parse(jsonFile);
        System.out.println("" + documentContext.read("$.a"));
        System.out.println("" + documentContext.read("$.b"));
        System.out.println("" + documentContext.read("$.d"));
    }
}

Обратите внимание, что я не создаю POJO, просто читаю заданные значения, используя функцию JSONPath аналогично XPath.То же самое вы можете сделать с Jackson:

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.File;

public class JsonPathApp {
    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        ObjectMapper mapper = new ObjectMapper();
        JsonNode root = mapper.readTree(jsonFile);
        System.out.println(root.get("a"));
        System.out.println(root.get("b"));
        System.out.println(root.get("d"));
    }
}

Нам не нужно JSONPath, потому что нужные нам значения находятся непосредственно в root узле.Как видите, API выглядит почти так же.Мы также можем создать POJO структуру:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.File;
import java.math.BigDecimal;

public class JsonPathApp {
    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        ObjectMapper mapper = new ObjectMapper();
        Pojo pojo = mapper.readValue(jsonFile, Pojo.class);
        System.out.println(pojo);
    }
}

@JsonIgnoreProperties(ignoreUnknown = true)
class Pojo {
    private Integer a;
    private BigDecimal b;
    private Integer d;

    // getters, setters
}

Несмотря на это, обе библиотеки позволяют считывать JSON полезную нагрузку непосредственно из URL. Я предлагаю скачать ее на другом шаге, используя лучший подход, который вы можете найти.Для получения дополнительной информации прочитайте эту статью: Загрузка файла с URL в Java .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...