亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java實(shí)現(xiàn)解析JSON大文件JsonReader工具詳解

 更新時(shí)間:2023年01月11日 09:59:00   作者:李奈 - Leemon  
這篇文章主要介紹了Java實(shí)現(xiàn)解析JSON大文件的工具JsonReader使用方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧

一,使用背景

之前遇到一個(gè)需求,是需要將一個(gè)json文件解析存儲(chǔ)到數(shù)據(jù)庫中。一開始測試的時(shí)候,json文件的大小都在幾兆以內(nèi),所以直接將json文件轉(zhuǎn)化為字符串,再轉(zhuǎn)化成JSONObject對象進(jìn)行處理時(shí)不會(huì)出現(xiàn)問題,如下所示:

File file = new File("")
try(FileInputStream fileInputStream = new FileInputStream(file)) {
    int size = fileInputStream.available();
    byte[] buffer = new byte[size];
    fileInputStream.read(buffer);
    String jsonString = new String(buffer, StandardCharsets.UTF_8);
    jsonString.replaceAll("\n", "");
    jsonString.replaceAll("\r", "");
    JSONObject json = JSON.parseObject(jsonString);
}

但是,當(dāng)出現(xiàn)幾十兆文件的時(shí)候,這時(shí)候就會(huì)報(bào)出內(nèi)存溢出的錯(cuò)誤

java.lang.OutOfMemoryError: Java heap space

雖然稍微大一點(diǎn)的文件,可以通過調(diào)整JVM參數(shù)來解決,如下所示

-Xms512m -Xmx2048m

但是這畢竟不是最合理的方法,因?yàn)楫?dāng)文件大到一定程度后,字節(jié)數(shù)組和字符串類型都存在接收不了的情況。因此,只能選擇另外的方式,此時(shí),Google的JsonReader是一個(gè)不錯(cuò)的解決方案。

二,JsonReader的使用

maven依賴如下:

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.6</version>
</dependency>

JsonReader讀取 JSON (RFC 7159) 編碼值作為令牌流。 此流包括文字 值(字符串、數(shù)字、布爾值和空值)以及開始和 對象和數(shù)組的結(jié)束分隔符。 令牌被遍歷 深度優(yōu)先順序,與它們在 JSON 文檔中出現(xiàn)的順序相同。 在 JSON 對象中,名稱/值對由單個(gè)標(biāo)記表示。

解析json

創(chuàng)建遞歸下降解析器 JSON ,首先創(chuàng)建 創(chuàng)建一個(gè)入口點(diǎn)方法 JsonReader.

每個(gè)對象類型和每個(gè)數(shù)組類型都需要一個(gè)方法。

  • 在 數(shù)組處理 方法中,首先調(diào)用 beginArray()消耗數(shù)組的左括號(hào)。 然后創(chuàng)建一個(gè)累積值的while循環(huán),在何時(shí)終止 hasNext()為false。 最后,通過調(diào)用讀取數(shù)組的右括號(hào) endArray()
  • 在 對象處理 方法中,首先調(diào)用 beginObject()消耗對象的左大括號(hào)。 然后創(chuàng)建一個(gè)while循環(huán)根據(jù)局部變量的名稱為其賦值。 這個(gè)循環(huán)應(yīng)該在什么時(shí)候終止 hasNext()為false。 最后,通過調(diào)用讀取對象的右括號(hào) endObject().

當(dāng)遇到嵌套對象或數(shù)組時(shí),委托給對應(yīng)的處理方法。

當(dāng)遇到未知名稱時(shí),嚴(yán)格的解析器應(yīng)該失敗并返回。 但寬松的解析器應(yīng)該調(diào)用 skipValue()遞歸地 跳過值的嵌套標(biāo)記,否則可能會(huì)發(fā)生沖突。

如果一個(gè)值可能為空,應(yīng)該首先檢查使用 peek(). 空字面量可以使用 nextNull()或者 skipValue().

例如,我之前要解析的json文件格式如下:

{
    "INFO": {
        "NAME": "",
        "Result": "",
        "Config": "",
        ...
    },
    "ATTR": {
        "key01": "val01",
        "key02": "val02",
        ...
    },
    "Parms": [
        {
            "k": "",
            "v": "",
            "p": "",
            "m": "",
            "l": ""
        },
        {
            "k": "",
            "v": "",
            "p": "",
            "m": "",
            "l": ""
        },
        ...
    ],
    "List": ["xxx", "xxxx", ...]
}

那按照J(rèn)sonReader解析的思路,我應(yīng)該先消費(fèi)整體對象的{,再逐個(gè)對INFO,ATTR,Parms,List進(jìn)行處理,總而言之,就是

String fileName = "";
FileReader in = new FileReader(fileName);
JsonReader reader = new JsonReader(in);
reader.beginObject();
String rootName = null;
while (reader.hasNext()) {
    rootName = reader.nextName();
    if("INFO".equals(rootName)) {
        reader.beginObject();
        while (reader.hasNext()) {
            System.out.println(reader.nextName() + ":" + reader.nextString())
        }
        reader.endObject();
    }else if("ATTR".equals(rootName)) {
        reader.beginObject();
        while (reader.hasNext()) {
            System.out.println(reader.nextName() + ":" + reader.nextString())
        }
        reader.endObject();
    }else if("Parms".equals(rootName)) {
        reader.beginArray();
        while (reader.hasNext()) {
            reader.beginObject();
            String k = null;
            while (reader.hasNext()) {
                k = reader.nextName();
                switch (k) {
                    case "k":
                        xxx;
                        break;
                    case "v":
                        xxx;
                        break;
                    case "p":
                        xxx;
                        break;
                    case "m":
                        xxx;
                        break;
                    case "l":
                        xxx;
                        break;
                    default:
                        reader.nextString();
                        break;
                }
            }
            reader.endObject();
        }
        reader.endArray();
    }else if("List".equals(rootName)) {
        reader.beginArray();
        while (reader.hasNext()) {
            System.out.println(reader.nextString());
        }
        reader.endArray();
    }else {
        reader.skipValue();
    }
}

常用方法如下所示:

方法名返回值描述
beginArray()void使用JSON流中的下一個(gè)令牌,并斷言它是新數(shù)組的開始。
endArray()void使用JSON流中的下一個(gè)令牌,并斷言它是當(dāng)前數(shù)組的結(jié)尾。
beginObject()void使用JSON流中的下一個(gè)令牌,并斷言它是新對象的開始。
endObject()void使用JSON流中的下一個(gè)令牌,并斷言它是當(dāng)前對象的結(jié)尾。
close()void關(guān)閉此 JSON閱讀器 和底層 Reader.
getPath()String返回JSON值中當(dāng)前位置的JsonPath。
hasNext()Boolean如果當(dāng)前數(shù)組或?qū)ο笥衅渌?,則返回true。
isLenient()Boolean如果此解析器在接受的內(nèi)容上是寬松的,則返回true。
setLenient(boolean lenient)void將此解析器配置為在其接受的內(nèi)容上寬松。
nextBoolean()boolean返回boolean下一個(gè)令牌的值,并使用它。
nextDouble()double返回double下一個(gè)令牌的值,并使用它。
nextInt()int返回int下一個(gè)令牌的值,并使用它。
nextLong()long返回long下一個(gè)令牌的值,并使用它。
nextName()String返回下一個(gè)標(biāo)記,即屬性名,并使用它。
nextNull()void使用JSON流中的下一個(gè)令牌,并斷言它是文本null。
nextString()String返回使用下一個(gè)標(biāo)記的字符串值。
peek()JsonToken返回下一個(gè)令牌的類型,而不使用它
skipValue()void遞歸跳過下一個(gè)值。

通過使用JsonReader,現(xiàn)在我解析幾十兆的文件基本沒有問題(上百兆的還沒嘗試過),一個(gè)44.5M的JSON文件在4秒就能夠處理完。

到此這篇關(guān)于Java實(shí)現(xiàn)解析JSON大文件JsonReader工具詳解的文章就介紹到這了,更多相關(guān)Java JsonReader內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java線程池ForkJoinPool實(shí)例解析

    Java線程池ForkJoinPool實(shí)例解析

    這篇文章主要介紹了Java線程池ForkJoinPool實(shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • Spring詳細(xì)解讀事務(wù)管理

    Spring詳細(xì)解讀事務(wù)管理

    Spring事務(wù)的本質(zhì)就是對數(shù)據(jù)庫事務(wù)的支持,沒有數(shù)據(jù)庫事務(wù),Spring是無法提供事務(wù)功能的。Spring只提供統(tǒng)一的事務(wù)管理接口,具體實(shí)現(xiàn)都是由數(shù)據(jù)庫自己實(shí)現(xiàn)的,Spring會(huì)在事務(wù)開始時(shí),根據(jù)當(dāng)前設(shè)置的隔離級(jí)別,調(diào)整數(shù)據(jù)庫的隔離級(jí)別,由此保持一致
    2022-04-04
  • spring中使用@Autowired注解無法注入的情況及解決

    spring中使用@Autowired注解無法注入的情況及解決

    這篇文章主要介紹了spring中使用@Autowired注解無法注入的情況及解決,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • java對接支付寶支付接口簡單步驟記錄

    java對接支付寶支付接口簡單步驟記錄

    最近項(xiàng)目APP需要接入微信、支付寶支付功能,在分配開發(fā)任務(wù)時(shí),聽說微信支付接口比支付寶支付接口要難實(shí)現(xiàn),這篇文章主要給大家介紹了關(guān)于java對接支付寶支付接口的簡單步驟,需要的朋友可以參考下
    2024-05-05
  • Springboot 接口對接文件及對象的操作方法

    Springboot 接口對接文件及對象的操作方法

    這篇文章主要介紹了Springboot 接口對接文件及對象的操作,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-07-07
  • thymeleaf實(shí)現(xiàn)前后端數(shù)據(jù)交換的示例詳解

    thymeleaf實(shí)現(xiàn)前后端數(shù)據(jù)交換的示例詳解

    Thymeleaf?是一款用于渲染?XML/XHTML/HTML5?內(nèi)容的模板引擎,當(dāng)通過?Web?應(yīng)用程序訪問時(shí),Thymeleaf?會(huì)動(dòng)態(tài)地替換掉靜態(tài)內(nèi)容,使頁面動(dòng)態(tài)顯示,這篇文章主要介紹了thymeleaf實(shí)現(xiàn)前后端數(shù)據(jù)交換,需要的朋友可以參考下
    2022-07-07
  • Java程序包不存在問題的解決辦法

    Java程序包不存在問題的解決辦法

    最近工作中遇到個(gè)問題,代碼中沒有報(bào)錯(cuò),啟動(dòng)時(shí)報(bào)錯(cuò),但是程序包不存在,這篇文章主要給大家介紹了關(guān)于Java程序包不存在問題的解決辦法,需要的朋友可以參考下
    2022-06-06
  • Spring MVC 自定義數(shù)據(jù)轉(zhuǎn)換器的思路案例詳解

    Spring MVC 自定義數(shù)據(jù)轉(zhuǎn)換器的思路案例詳解

    本文通過兩個(gè)案例來介紹下Spring MVC 自定義數(shù)據(jù)轉(zhuǎn)換器的相關(guān)知識(shí),每種方法通過實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2021-09-09
  • 淺談java 面對對象(抽象 繼承 接口 多態(tài))

    淺談java 面對對象(抽象 繼承 接口 多態(tài))

    下面小編就為大家?guī)硪黄獪\談java 面對對象(抽象 繼承 接口 多態(tài))。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-02-02
  • Java找不到或無法加載主類及編碼錯(cuò)誤問題的解決方案

    Java找不到或無法加載主類及編碼錯(cuò)誤問題的解決方案

    今天小編就為大家分享一篇關(guān)于Java找不到或無法加載主類及編碼錯(cuò)誤問題的解決方案,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-02-02

最新評論