优化的JSON文件读写方式

huangapple go评论83阅读模式
英文:

Optimized way of writing/reading json file

问题

所以我有大型的JSON文件(其中包含JSON对象列表),我需要:

  • 添加/删除文件列表中的对象
  • 更新对象的值(具体而言,这些对象可以有对象列表,我可能需要向该列表中添加或删除元素)
  • 读取文件中的每个对象(在这里,我希望仅为每个对象加载文件,以便我不必将整个文件加载到RAM中,要注意这些文件非常大)

以下是文件的示例:

[
    {
        "id": "1",
        "list": [
            { "id": "1", "example": "example" },
            { "id": "2", "example": "example" }
        ]
    },
    {
        "id": "2",
        "list": [
            { "id": "1", "example": "example" },
            { "id": "2", "example": "example" }
        ]
    },
    {
        "id": "3",
        "list": [
            { "id": "1", "example": "example" },
            { "id": "2", "example": "example" }
        ]
    },
    ...
]

对于更新数组的部分,我考虑过读取对象,然后更改数组并将整个对象替换为文件中的内容(这可能有效,但我也可以接受更好的解决方案)。

我该如何做到这一点?(我正在使用Java)

好的,目前我找到了一种在JSON文件中写入数据的方法,但不能追加数据(这正是我所需的)。以下是我的代码:

public void create(JSONObject document) {
    try {
        FileWriter fw = new FileWriter(new File(collectionPath));
        JSONWriter jsonWriter = new JSONWriter(fw);
        jsonWriter.object();
        Iterator<String> keys = document.keys();
        while (keys.hasNext()) {
            String key = keys.next();
            jsonWriter.key(key);
            jsonWriter.value(document.get(key));
        }
        jsonWriter.endObject();
        fw.flush();
        fw.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

通过这种方式,我写入了文件,但我需要追加数据,而不是覆盖已经写入的数据(因为这会将已有的数据替换为新数据,而我不想这样做)。

以下是文件的示例,请注意,这只是一个示例,实际文件可能甚至有几GB大小。

{
    "uid": "1",
    "password": ["keyboardcat", "keyboardcat1"],
    "nestedObject": {
        "bool": true,
        "string": "stringa",
        "int": 1,
        "object": {
            "bool": true,
            "string": "stringa",
            "int": 1
        }
    },
    "username": "test"
}
英文:

So i have large JSON files (which contain a list of JSON object) and i have to:

  • add/remove objects from the file's list of JSON objects
  • update object's values (specifically this objects can have list of objects and i might have to add or remove elements from this list)
  • read each object in the file (here i would like to load only the file for each object so that i don't have to load the whole file in the RAM keep in mind that this files are very heavy)

Here you can find an example of the file:

[

{
     &quot;id&quot;:&quot;1&quot;,
     &quot;list&quot;:[
         { &quot;id&quot;: &quot;1&quot;, &quot;example&quot;: &quot;example&quot; }, { &quot;id&quot;: &quot;2&quot;, &quot;example&quot;: &quot;example&quot; }
     ]
},
{
     &quot;id&quot;:&quot;2&quot;,
     &quot;list&quot;:[
         { &quot;id&quot;: &quot;1&quot;, &quot;example&quot;: &quot;example&quot; }, { &quot;id&quot;: &quot;2&quot;, &quot;example&quot;: &quot;example&quot; }
     ]
},
{
     &quot;id&quot;:&quot;3&quot;,
     &quot;list&quot;:[
         { &quot;id&quot;: &quot;1&quot;, &quot;example&quot;: &quot;example&quot; }, { &quot;id&quot;: &quot;2&quot;, &quot;example&quot;: &quot;example&quot; }
     ]
},
...
]

For the part of updating the array i have tought of reading the object then change the array and replace the entire object in the file (it may work but i am open to better solutions).

How can i do this? (I am using Java)

Ok so currently i found a way of writing in the JSON file but not appending data to it (this is what i need) here is my code:

public void create(JSONObject document){
        try {
            FileWriter fw = new FileWriter(new File(collectionPath));
            JSONWriter jsonWriter = new JSONWriter(fw);
            jsonWriter.object();
            Iterator&lt;String&gt; keys = document.keys();
            while(keys.hasNext()){
                String key = keys.next();
                jsonWriter.key(key);
                jsonWriter.value(document.get(key));
            }
            jsonWriter.endObject();
            fw.flush();
            fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

By doing this i write the file and i need to append the data not to write it (cause this replaces the already written data with the new data and i don't want this).

This is an example of the file keep in mind that this is an example and the real one could weight event gigabytes.

{&quot;uid&quot;:&quot;1&quot;,&quot;password&quot;:[&quot;keyboardcat&quot;,&quot;keyboardcat1&quot;],&quot;nestedObject&quot;:{&quot;bool&quot;:true,&quot;string&quot;:&quot;stringa&quot;,&quot;int&quot;:1,&quot;object&quot;:{&quot;bool&quot;:true,&quot;string&quot;:&quot;stringa&quot;,&quot;int&quot;:1}},&quot;username&quot;:&quot;test&quot;}

答案1

得分: 1

jackson-core网站上用法,简单读取章节中,提供了一个读写事件流的示例,您可以了解如何高效地读取大型JSON文件。您基本上会逐一读取数组项,根据需要进行更改,然后将它们写入新文件;如果您需要删除某些项,您将在读取&写入(也就是复制)原始文件中的适当数量的项时省略写入它们;当您需要插入新项时,您只需在读取&写入(也就是复制)原始文件中的适当数量的项后将它们写入。最后,您可以用新文件替换原始文件。

以下是编写大型对象数组(这里使用HashMap,但也可以是其他任何对象)的示例,使用writePOJOField方法。我使用jackson-corejackson-databind(请参见https://github.com/FasterXML/jackson)。

// 给定
ByteArrayOutputStream stream = new ByteArrayOutputStream();
JsonFactory jfactory = new JsonFactory(new ObjectMapper());
JsonGenerator jGenerator = jfactory.createGenerator(stream, JsonEncoding.UTF8);

// 当
jGenerator.writeStartObject();
jGenerator.writeStringField("name", "Tom");
jGenerator.writeNumberField("age", 25);

jGenerator.writeFieldName("objects");
jGenerator.writeStartArray();
IntStream.range(0, 3).forEach(it -> {
    try {
        jGenerator.writePOJO(new HashMap<String, String>() {{
            put("key1", "value1");
            put("key2", "value2");
        }});
    } catch (IOException e) {
        e.printStackTrace();
        throw new RuntimeException(e);
    }
});
jGenerator.writeEndArray();

jGenerator.writeFieldName("strings");
jGenerator.writeStartArray();
jGenerator.writeString("textX");
jGenerator.writeString("textY");
IntStream.range(0, 3).forEach(it -> {
    try {
        jGenerator.writeString("text-" + it);
    } catch (IOException e) {
        e.printStackTrace();
        throw new RuntimeException(e);
    }
});
jGenerator.writeEndArray();

jGenerator.writeNullField("nullField");
jGenerator.writeEndObject();
jGenerator.close();
英文:

On the jackson-core site, at Usage, simple reading chapter, the Reading and Writing Event Streams example is provided where one can see how to read a large json file efficiently. You'll basically read the array items one by one, change them if you need to and then write them to a new file; if you need to remove some items you'll simply omit writing them while when you have to insert new items you'll simply write them after reading&writing (aka copying) the appropriate number of items from the original file. In the end you can replace the original file with the new one.

Below is an example of writing a large array of objects (HashMap here but could be any other) with writePOJOField method. I use jackson-core and jackson-databind (see https://github.com/FasterXML/jackson).

// given
ByteArrayOutputStream stream = new ByteArrayOutputStream();
JsonFactory jfactory = new JsonFactory(new ObjectMapper());
JsonGenerator jGenerator = jfactory.createGenerator(stream, JsonEncoding.UTF8);

// when
jGenerator.writeStartObject();
jGenerator.writeStringField(&quot;name&quot;, &quot;Tom&quot;);
jGenerator.writeNumberField(&quot;age&quot;, 25);

jGenerator.writeFieldName(&quot;objects&quot;);
jGenerator.writeStartArray();
IntStream.range(0, 3).forEach(it -&gt; {
    try {
        jGenerator.writePOJO(new HashMap&lt;String, String&gt;() {{
            put(&quot;key1&quot;, &quot;value1&quot;);
            put(&quot;key2&quot;, &quot;value2&quot;);
        }});
    } catch (IOException e) {
        e.printStackTrace();
        throw new RuntimeException(e);
    }
});
jGenerator.writeEndArray();

jGenerator.writeFieldName(&quot;strings&quot;);
jGenerator.writeStartArray();
jGenerator.writeString(&quot;textX&quot;);
jGenerator.writeString(&quot;textY&quot;);
IntStream.range(0, 3).forEach(it -&gt; {
    try {
        jGenerator.writeString(&quot;text-&quot; + it);
    } catch (IOException e) {
        e.printStackTrace();
        throw new RuntimeException(e);
    }
});
jGenerator.writeEndArray();

jGenerator.writeNullField(&quot;nullField&quot;);
jGenerator.writeEndObject();
jGenerator.close();

答案2

得分: 0

如果您使用org.json.JSONObject,请尝试使用org.json.JSONTokener进行读取:

读取部分:

public static JSONObject getJSONFromFile(String path){
    JSONObject result ;
    Path resultPath = Paths.get(path);
    try {
        InputStream stream = Files.newInputStream(resultPath);
        result = new JSONObject(new JSONTokener(stream));
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    return result;
}

写入部分:

public static void writeJSON(JSONObject json, String path){
    Path filePath = Paths.get(path);
    if(Files.exists(filePath))
    {
        try(FileWriter writer = new FileWriter(filePath.toFile())){
            writer.write(json.toString(4));
            writer.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
英文:

If You use org.json.JSONObject then try this org.json.JSONTokener

for read :

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-html -->

public static JSONObject getJSONFromFile(String path){
        JSONObject result ;
        Path resultPath = Paths.get(path);
        try {
            InputStream stream = Files.newInputStream(resultPath);
            result = new JSONObject(new JSONTokener(stream));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return result;
    }

<!-- end snippet -->

for write :

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-html -->

public static void writeJSON(JSONObject json, String path){
        Path filePath = Paths.get(path);
        if(Files.exists(filePath))
        {
            try(FileWriter writer = new FileWriter(filePath.toFile())){
                writer.write(json.toString(4));
                writer.flush();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

<!-- end snippet -->

huangapple
  • 本文由 发表于 2020年7月27日 00:55:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/63103100.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定