【问题标题】:Java - Write in a Json with JacksonJava - 与 Jackson 一起编写 Json
【发布时间】:2023-03-08 02:31:01
【问题描述】:

我目前正在为学校做一个项目,我正在尝试在我的 json 文件末尾(在卡片属性中)编写一个对象,而无需使用 Jackson 库重写所有内容。

问题是,当我尝试执行此操作时,我的对象写入正确,但它写在文件末尾,我尝试将其放入卡片列表 [ THERE ]。

有人有想法吗?谢谢。

编辑:我已经知道如何通过重写来写入文件,为了回答我老师的指示,我需要在不重写文件的情况下这样做。

我的 Json 文件:

{

  "cards": [
    {
      "subject": "The Earth",
      "questions": [
        {
          "challenge": "What is the highest mountain of the world?",
          "answer": "Everest"
        },
        {
          "challenge": "What is the largest ocean in the world?",
          "answer": "Pacific Ocean"
        }
      ],
      "author": "Roger",
      "theme": "IMPROBABLE"
    },

    {
      "subject": "Holidays",
      "questions": [
        {
          "challenge": "What is the most touristic country in the world?",
          "answer": "France"
        },
        {
          "challenge": "In 2019, how many pictures did vacationers take per day?",
          "answer": "55"
        }
      ],
      "author": "Roger",
      "theme": "PLEASURE"
    }
    
  ]

}

我的主班:

public class Main {
  
  public static void main(String[] args) {
    Question question1 = new Question("Roger", Theme.SCHOOL, "Test", "c1", "a1");
    Question question2 = new Question("Roger", Theme.SCHOOL, "Test", "c2", "a2");

    BasicCard bc = new BasicCard("Roger", Theme.SCHOOL, "Test", Arrays.asList(question1,question2));
    
    try {
          File file = new File(Constants.DECK_PATH);
          FileWriter fileWriter = new FileWriter(file, true);

          ObjectMapper mapper = new ObjectMapper();
          SequenceWriter seqWriter = mapper.writerWithDefaultPrettyPrinter().writeValues(fileWriter);
          seqWriter.write(bc);
          seqWriter.close();
      } catch (IOException e) {
          e.printStackTrace();
      }

  }

}

结果

{

  "cards": [
    {
      "subject": "The Earth",
      "questions": [
        {
          "challenge": "What is the highest mountain of the world?",
          "answer": "Everest"
        },
        {
          "challenge": "What is the largest ocean in the world?",
          "answer": "Pacific Ocean"
        }
      ],
      "author": "Roger",
      "theme": "IMPROBABLE"
    },

    {
      "subject": "Holidays",
      "questions": [
        {
          "challenge": "What is the most touristic country in the world?",
          "answer": "France"
        },
        {
          "challenge": "In 2019, how many pictures did vacationers take per day?",
          "answer": "55"
        }
      ],
      "author": "Roger",
      "theme": "PLEASURE"
    }
  ]
}{
  "subject" : "Test",
  "questions" : [ {
    "challenge" : "c1",
    "answer" : "a1"
  }, {
    "challenge" : "c2",
    "answer" : "a2"
  }, {
    "challenge" : "c3",
    "answer" : "a3"
  }, {
    "challenge" : "c4",
    "answer" : "a4"
  } ],
  "author" : "Damien",
  "theme" : "SCHOOL"
}

【问题讨论】:

  • 您可以创建一个新类来表示 json 的字段。然后,您可以读取 json 文件并使用 objectMapper 将 json 转换为您的对象。在此之后,您可以将卡片添加到列表中并再次使用 objectMapper 将您的对象序列化为 json。
  • 但是文件是这样重写的。我想插入我的元素。

标签: java json jackson overwrite write


【解决方案1】:

这里的问题是两层之间的分离:

  1. 文件系统,在您的情况下是通过FileWriter 提供的
  2. 逻辑层 (json),在您的情况下是通过 Jackson (ObjectMapper) 提供的

您当前附加在较低层 (1. The filesystem)。这一层不知道你要写json。它甚至不知道 json 是什么。它只是让您将更多字节附加到现有文件的末尾。

您想要的是附加到现有的 json 结构。为此,您必须读入现有对象,将所需对象附加到其中,并通过将更新后的对象写入文件系统来完全替换文件。

    public static void main(String[] args) {
        Question question1 = new Question("Roger", Theme.SCHOOL, "Test", "c1", "a1");
        Question question2 = new Question("Roger", Theme.SCHOOL, "Test", "c2", "a2");

        BasicCard bc = new BasicCard("Roger", Theme.SCHOOL, "Test", Arrays.asList(question1,question2));
        
        ObjectMapper mapper = new ObjectMapper();
        File file = new File(Constants.DECK_PATH);

        try {
            // read the existing object from the file
            Map<String, List<BasicCard>> object = mapper.readValue(file, new TypeReference<Map<String, List<BasicCard>>>(){});
            // append your BasicCard bc to the list
            object.computeIfAbsent("cards", k -> new ArrayList<>()).add(bc);
            
            // override the contents of the file by writing the object entirely again
            mapper.writeValue(file, object);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

【讨论】:

  • 我真正想做的不是重写所有内容。难道就没有别的办法了吗?
  • 如果你的对象这么小(我会说所有低于 5 兆字节的东西)-> 不要过于复杂。是的,有一些方法可以在文件系统上更有效地工作(不是每次都替换整个对象)......但除非你在一个紧密的循环中这样做或处理非常大的文件,否则它们不值得麻烦
  • 我知道,但这是我老师的指示,不是选择
  • 最简单的方法是放弃漂亮的打印(每个 Card-Object 都打印在一行中)。然后你可以简单地在每张卡上附加一行。请注意,整个文件将不是有效的 json。该文件中的每一行都是有效的 json 对象,但整个文件不是。另一种但更高级的方法是寻找能够直接在文件系统上工作的库,而无需读取现有对象。您可以通过 JSONpath-syntax 或类似方式指定“目标”,并允许您直接在文件中添加到现有结构。
  • 我刚刚搜索了一下,发现了一个名为jq 的命令行工具。有使用围绕它构建的 JNI 的 java 包装器。看起来 jq 可以使用jq .cards += {.. your json card object ..} 之类的命令执行您想要的操作
【解决方案2】:

您可以使用以下内容将 json 附加到现有文件中。

void write() {
    ObjectMapper om = new ObjectMapper()
    ObjectNode original = om.readValue(new File("oldFile.json"), ObjectNode)

    Subject s = new Subject(List.of(new Question("c1", "a1"),
                             new Question("c2", "a2")), "Test")

    original.set("questions", om.valueToTree(s))

    om.writeValue(new File("newFile.json"), original)
}

【讨论】:

  • 我已经知道如何通过重写来写入文件,为了回答老师的指示,我需要在不重写文件的情况下这样做。
  • 无论是重写文件还是重新创建新文件。我不完全确定..但我认为像 JQ 这样的工具会验证整个文件并重新创建临时文件,然后才能将某些内容附加到末尾
  • 一个技巧可以将原始 json 视为纯文本文件,将最后一个 } 替换为逗号 , 您的新 json 部分,然后是 }
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-05
  • 2017-08-29
  • 1970-01-01
  • 2014-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多