【问题标题】:What’s the best way to load a JSONObject from a json text file?从 json 文本文件加载 JSONObject 的最佳方法是什么?
【发布时间】:2011-11-19 18:36:59
【问题描述】:

将包含 JSON 的文件加载到 JSONObject 中的最简单方法是什么。

目前我正在使用 json-lib。

这是我所拥有的,但它会引发异常:

XMLSerializer xml = new XMLSerializer();
JSON json = xml.readFromFile("samples/sample7.json”);     //line 507
System.out.println(json.toString(2));

输出是:

Exception in thread "main" java.lang.NullPointerException
    at java.io.Reader.<init>(Reader.java:61)
    at java.io.InputStreamReader.<init>(InputStreamReader.java:55)
    at net.sf.json.xml.XMLSerializer.readFromStream(XMLSerializer.java:386)
    at net.sf.json.xml.XMLSerializer.readFromFile(XMLSerializer.java:370)
    at corebus.test.deprecated.TestMain.main(TestMain.java:507)

【问题讨论】:

  • 你为什么对 JSON 文件使用 XMLSerializer?
  • 这是我唯一能找到它读取文件的地方,Javadoc 说:readFromFile(String path) Creates a JSON value from a File.
  • 我明白了,我可能只是将文件作为普通文本读取,转换为字符串,然后转换为 JSONObject。但是,我发现您已经有了比这更好的解决方案 :)

标签: java json


【解决方案1】:

感谢@Kit Ho 的回答。我使用了您的代码,发现在创建 JSONObject 时我的 InputStream 始终为 null 和 ClassNotFound 异常时遇到错误。这是我的代码版本,对我有用:

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import org.apache.commons.io.IOUtils;

import org.json.JSONObject;
public class JSONParsing {
    public static void main(String[] args) throws Exception {
        File f = new File("file.json");
        if (f.exists()){
            InputStream is = new FileInputStream("file.json");
            String jsonTxt = IOUtils.toString(is, "UTF-8");
            System.out.println(jsonTxt);
            JSONObject json = new JSONObject(jsonTxt);       
            String a = json.getString("1000");
            System.out.println(a);   
        }
    }
}

我发现这个答案对difference between FileInputStream and getResourceAsStream 很有启发性。希望这对其他人也有帮助。

【讨论】:

  • 我不是 Java 开发人员,现在没有时间研究它,但您可能想查看the rejected suggested edit to this post,它声称在您的代码中修复了竞争条件(据我了解,file.json 可能会在f.exists() 调用和读取文件之间被删除,因此使用 try/catch 更好)并考虑实施更改。另外:您的答案已在 The Daily WTF 论坛上提及:what.thedailywtf.com/t/…。恭喜?
  • @MarkAmery 是的,这是一个经典的 time of check to time of use 错误。此外,“抛出异常”通常在 main 中是一件坏事。
  • 不知何故,我错过了对我的评论明显的编辑迷你战争。哈。感谢dailywtf链接......相当可疑的成就。所以我可以理解我是如何搞砸的,正是这一行导致代码容易受到 TOCTOU 错误的影响: InputStream is = new FileInputStream("file.json") 重新打开文件,它可能已经从我的初始 f.exists() 检查?
  • @janoulle 是的,完全正确。出于这个原因,与其检查文件是否存在并继续并在存在时使用它,不如try 使用该文件并在它发生时处理FileNotFoundException 被认为是更好的做法。当然,通常——甚至可能通常——这在实践中根本不重要,因为你知道如果文件存在的话,没有什么可以从你脚下抢走文件,或者因为你不知道'不在乎您的程序是否在这种极端情况下崩溃。但由于 try/catch 方法没有缺点,我们不妨在这里展示最佳实践。
  • 正如@MarkAmery 所说的那样——这极不可能发生,但是一旦发生,它真的会让你陷入困境。所以是的,最好的做法通常是甚至不检查(除非您出于其他原因进行检查)并让异常在实际无法读取时发生,然后在该 catch 块中处理丢失的文件情况。跨度>
【解决方案2】:

试试这个:

import net.sf.json.JSONObject;
import net.sf.json.JSONSerializer;
import org.apache.commons.io.IOUtils; 

    public class JsonParsing {

        public static void main(String[] args) throws Exception {
            InputStream is = 
                    JsonParsing.class.getResourceAsStream( "sample-json.txt");
            String jsonTxt = IOUtils.toString( is );

            JSONObject json = (JSONObject) JSONSerializer.toJSON( jsonTxt );        
            double coolness = json.getDouble( "coolness" );
            int altitude = json.getInt( "altitude" );
            JSONObject pilot = json.getJSONObject("pilot");
            String firstName = pilot.getString("firstName");
            String lastName = pilot.getString("lastName");

            System.out.println( "Coolness: " + coolness );
            System.out.println( "Altitude: " + altitude );
            System.out.println( "Pilot: " + lastName );
        }
    }

这是你的 sample-json.txt ,应该是 json 格式

{
 'foo':'bar',
 'coolness':2.0,
 'altitude':39000,
 'pilot':
     {
         'firstName':'Buzz',
         'lastName':'Aldrin'
     },
 'mission':'apollo 11'
}

【讨论】:

  • 哪些包是:IOUtils 和 JsonParsing from?
  • 导入 net.sf.json.JSONObject;导入 net.sf.json.JSONSerializer;导入 org.apache.commons.io.IOUtils;顺便说一句,你也可以使用simple-json.jar,使用相同的东西,你可以在互联网上搜索。 code.google.com/p/json-simple
  • 好的,谢谢,但我仍然无法解决“JsonParsing”,有什么想法吗?
  • @Larry JsonParsing 是您的实际班级名称。在此示例中,公共类 JsonParsing = JsonParsing.class.getRe...
  • 嗨拉里,JsonParsing 是类名,你可以在代码中使用你的类名。
【解决方案3】:

使用 java 8 你可以试试这个:

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class JSONUtil {

    public static JSONObject parseJSONFile(String filename) throws JSONException, IOException {
        String content = new String(Files.readAllBytes(Paths.get(filename)));
        return new JSONObject(content);
    }

    public static void main(String[] args) throws IOException, JSONException {
        String filename = "path/to/file/abc.json";
        JSONObject jsonObject = parseJSONFile(filename);

        //do anything you want with jsonObject
    }
}

【讨论】:

【解决方案4】:

另一种方法是使用 Gson 类

String filename = "path/to/file/abc.json";
Gson gson = new Gson();
JsonReader reader = new JsonReader(new FileReader(filename));
SampleClass data = gson.fromJson(reader, SampleClass.class);

这将给出解析json字符串后获得的对象。

【讨论】:

  • 什么是 SampleClass?
  • 它是一个虚拟的类名,无论你想将 json 解析成哪个类。你可以用你的类名替换SampleClass。希望它清楚。
【解决方案5】:

Google'e Gson 库中,用于拥有 JsonObject,或更抽象的 JsonElement

import com.google.gson.JsonElement;
import com.google.gson.JsonParser;

JsonElement json = JsonParser.parseReader( new InputStreamReader(new FileInputStream("/someDir/someFile.json"), "UTF-8") );

这不需要给定的对象结构来接收/读取 json 字符串。

编辑 2021 年 5 月 13 日: 正如我自己评论的那样:此解决方案无法正确处理关闭流!
这样做:

JsonElement json = null;
try (Reader reader = new InputStreamReader(new FileInputStream("/someDir/someFile.json"), "UTF-8")) {
    json = JsonParser.parseReader( reader );
} catch (Exception e) {
    // do something
}

正如人们所看到的那样,代码在正确执行时会变得臃肿。我会清理代码将“从文件加载 json”移动到 FileUtils.class 中;这可能已经存在并且可以进行非常好的可调节异常处理...

【讨论】:

  • 大约 7 个月后,我看到了一些不利因素:流没有被关闭。尽管如此,理论上我希望默认行为会通过底层消费实例关闭流。因为这个实例知道它什么时候完成,并且大多数时候流将不再被使用......另一方面,这不是消费者的责任,因为我也遵循这个想法:'谁打开需要关闭'它是两难:-(
【解决方案6】:

我正在使用的 json 示例:

"identity" : {
  "presentProvince" : [ {
    "language" : "eng",
    "value" : "China"
  } ],
  "presentAddressLine1" : [ {
    "language" : "eng",
    "value" : "bjbjbhjbhj"
  } ],
 "permanentAddressLine4" : [ {
    "language" : "eng",
    "value" : "123456"
  } ]
} } 

这里是访问语言和值的代码:

public static void JsonObjParsing() throws Exception {
    File f = new File("id.json");
    if (f.exists()){
        InputStream is = new FileInputStream(f);
        String jsonTxt = IOUtils.toString(is, "UTF-8");
        System.out.println(jsonTxt);
            
            
        JSONObject json = new JSONObject(jsonTxt); 
           
        JSONObject identity = json.getJSONObject("identity");
            
            
        JSONArray identityitems = identity.getJSONArray("presentProvince");
        for (Object o : identityitems) {
            JSONObject jsonLineItem = (JSONObject) o;
            String language = jsonLineItem.getString("language");
            String value = jsonLineItem.getString("value");
            System.out.println(language +" " + value);
        }
    } 
}


public static void main(String[] args) throws Exception {
    JsonObjParsing();
}

【讨论】:

  • @svarog 谢谢
【解决方案7】:

在文件中获取 json 数组或仅获取 json 的方法是

InputStream inputStream= Employee.class.getResourceAsStream("/file.json");
CollectionType collectionType = mapper.getTypeFactory().constructCollectionType(List.class, Employee.class);

List<Employee> lstEmployees = mapper.readValue(inputStream, collectionType);

file.json 需要放在资源文件夹中。如果您的文件只有一个没有 json 数组方括号 [] 的 json 块,则可以跳过 CollectionType

InputStream inputStream= Employee.class.getResourceAsStream("/file.json");
Employee employee = mapper.readValue(inputStream, Employee.class);

另请参阅此处以获取我绘制的原始answer

【讨论】:

    猜你喜欢
    • 2016-10-03
    • 1970-01-01
    • 2019-07-11
    • 2019-08-13
    • 2021-01-14
    • 2012-06-10
    • 1970-01-01
    • 2021-12-09
    • 2010-11-06
    相关资源
    最近更新 更多