Создание, запись, редактирование файла JSON в Android Studio

Я хотел бы создать файл JSON во внутренней памяти телефона для хранения данных. Я хочу иметь возможность добавлять объекты (configX) в файл, а затем читать данные.

Это должно выглядеть примерно так:

{

  "config1": {

    "component1": "url",
    "component2": "url",
    "component3": "url"

  },

  "config2": {

    "component1": "url",
    "component2": "url",
    "component3": "url"

  }

}

Я могу создать файл JSON следующим образом:

public void saveToJson(){
    JSONObject json = new JSONObject();
    try {
        json.put("component1", "url");
        json.put("component2", "url");

        String jsonString = json.toString();
        
        FileOutputStream fos = this.openFileOutput("jsonfile", Context.MODE_PRIVATE);
        fos.write(jsonString.getBytes());
        fos.close();

        Log.d("JSON" , json.toString());

    } catch (IOException | JSONException e) {
        e.printStackTrace();
    }
}

Но как поместить компоненты в объект конфигурации? И как восстановить данные?

ИЗМЕНИТЬ 1:

https://stackoverflow.com/a/62474912/11652860

Спасибо за очень подробный ответ, я что-то не так делаю. У меня есть действие, в котором я помещаю и сохраняю данные в файл json:

public class Data {

        private Map<String, Map<String, String>> map;

        public Data() {

        }

        public Data(Map<String, Map<String, String>> map) {
            this.map = map;
        }

        public Map<String, Map<String, String>> getMap() {
            return map;
        }

        public void setMap(Map<String, Map<String, String>> map) {
            this.map = map;
        }

    }
Map<String, String> config1 = new HashMap<>();
config1.put("component1", "url1");
config1.put("component2", "url1");
config1.put("component3", "url1");

Map<String, Map<String, String>> map = new HashMap<>();
map.put("config1", config1);

Data data = new Data(map);

Gson gson = new Gson();
String json = gson.toJson(data);

FileOutputStream fos = null;
 try {
fos = webViewActivity.this.openFileOutput("jsonfile", Context.MODE_PRIVATE);
} catch (FileNotFoundException e) {
 e.printStackTrace();
}
 try {
 fos.write(json.getBytes());
} catch (IOException e) {
  e.printStackTrace();
}
 try {
 fos.close();
} catch (IOException e) {
 e.printStackTrace();
}

И фрагмент, где я загружаю данные:

public class Data {

        private Map<String, Map<String, String>> map;

        public Data() {

        }

        public Data(Map<String, Map<String, String>> map) {
            this.map = map;
        }

        public Map<String, Map<String, String>> getMap() {
            return map;
        }

        public void setMap(Map<String, Map<String, String>> map) {
            this.map = map;
        }

    }
 public void load(){
        FileInputStream fis = null;

        try {

            fis = getContext().openFileInput("jsonfile.txt");
            InputStreamReader isr = new InputStreamReader(fis);
            BufferedReader br = new BufferedReader(isr);

            StringBuilder sb = new StringBuilder();
            String text;

            while ((text = br.readLine()) != null){
                sb.append(text).append("\n");

                Gson gson = new Gson();

                String json = gson.toJson(text);
                Data data = gson.fromJson(json, Data.class);

                String url = data.getMap().get("config1").get("component1");

                frameTV.setText(url);

            }


        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

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

ИЗМЕНИТЬ 2:

Я нашел проблему, я не загружал и не сохранял должным образом:

СОХРАНЕНИЕ:

String filename = "jsonfile.txt";

FileOutputStream outputStream;

try {
   outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
   outputStream.write(json.getBytes());
   outputStream.close();
} catch (Exception e) {
   e.printStackTrace();
}

ЗАГРУЗКА:

FileInputStream fis = getContext().openFileInput("jsonfile.txt");
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader bufferedReader = new BufferedReader(isr);
StringBuilder sb = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
    sb.append(line);
}

String json = sb.toString();

Gson gson = new Gson();
Data data = gson.fromJson(json, Data.class);
String priceURL = data.getMap().get("config1").get("url1");

ИЗМЕНИТЬ 3:

Теперь моя проблема в том, что мне нужно создать файл один раз, а затем проверить, существует ли файл, если это так, мне нужно проверить, существует ли config1, если нет, мне нужно поместить config в файл.

Но я не могу проверить, существует ли config1, потому что я получаю: java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.Map com.a.app.ui.app.appFragment$Data.getMap()

Я проверяю, существует ли он, выполнив:

Boolean configTest = data.getMap().containsKey("config1");
if(!configTest){}

Как я могу создать файл и проверить данные, не получая исключение NullPointerException?

Спасибо за помощь мне !


person Oliver    schedule 19.06.2020    source источник


Ответы (3)


В этом случае поможет библиотека Google Gson.

  1. Добавьте зависимость для Google Gson в свой файл radle.
    dependencies {
      implementation 'com.google.code.gson:gson:2.8.6'
    }
  1. Создайте класс для вашего контейнера данных
    public class Data {

        private Map<String, Map<String, String>> map;

        public Data() {
        }

        public Data(Map<String, Map<String, String>> map) {
            this.map = map;
        }

        public Map<String, Map<String, String>> getMap() {
            return map;
        }

        public void setMap(Map<String, Map<String, String>> map) {
            this.map = map;
        }
    }
  1. Добавьте данные в свой класс
    Map<String, String> config1 = new HashMap<>();
    config1.put("component1", "url1");
    config1.put("component2", "url1");
    config1.put("component3", "url1");

    Map<String, String> config2 = new HashMap<>();
    config2.put("component1", "url1");
    config2.put("component2", "url1");
    config2.put("component3", "url1");

    Map<String, Map<String, String>> map = new HashMap<>();
    map.put("config1", config1);
    map.put("config2", config2);

    Data data = new Data(map);
  1. Получить gson из класса данных
Gson gson = new Gson();
String json = gson.toJson(data);
  1. Теперь вы можете сохранить этот json в файл в текстовом формате.

  2. Теперь при чтении загрузите содержимое текстового файла в строку, скажем, «jsonString».

  3. Десериализовать jsonString в объект Java

Data data = gson.fromJson(json, Data.class);
  1. Конфигурации доступа
String url = data.getMap().get("config1").get("component1");
  1. Добавить новые конфигурации
    Map<String, String> config3 = new HashMap<>();
    config3.put("component1", "url1");
    config3.put("component2", "url1");
    config3.put("component3", "url1");

    data.getMap().put("config3", config3);

  1. Повторите эти шаги, чтобы сохранить конфигурации

  2. Или Вы можете вручную отредактировать текстовый файл, чтобы добавить конфигурации в соответствии с предопределенным форматом.

    {
       "maps":{
          "config2":{
             "component1":"url1",
             "component2":"url1",
             "component3":"url1"
          },
          "config1":{
             "component1":"url1",
             "component2":"url1",
             "component3":"url1"
          }
       }
    }
person arnabmaji19    schedule 19.06.2020
comment
Единственное, я не могу добавить компоненты 4,5,6, потому что они заменяют компоненты 1,2,3: map.put("config1", config1); это проблема, как я могу это решить? - person Oliver; 19.06.2020
comment
Если вы хотите добавить больше компонентов в config1, после загрузки класса данных просто выполните data.getMap().get(config1).put(component4, url4); и пересохраните файл. Напоминаем, что вы также можете добавить компоненты вручную, отредактировав файл json и добавив еще одну пару ключ-значение в config1. - person arnabmaji19; 20.06.2020
comment
По какой-то причине, когда я запускаю код на другом эмуляторе, я получаю эту ошибку: jsonfile.txt: open failed: ENOENT (No such file or directory) Похоже, он не создает текстовый файл, но когда я пытаюсь его создать, он все равно не работает, я получаю java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.Map com.a.app.ui.app.appFragment$Data.getMap()' on a null object reference - person Oliver; 20.06.2020
comment
Возможно, это связано с тем, что при смене устройств файл json сначала не существует. Если вы создадите пустой файл, десериализация завершится ошибкой, вызвав исключение нулевого указателя, потому что он просто не сможет создать объект из пустого файла. Вам необходимо инициализировать объект вручную хотя бы один раз, а затем сохранить его. Если ваш файл конфигурации не нужно менять каждый раз, когда вы меняете устройство, вы можете просто поместить файл в папку с ресурсами, что позволит упаковать файл с apk. - person arnabmaji19; 21.06.2020
comment
Спасибо, я решил проблему с: File file = getContext().getFileStreamPath(FILE_NAME);, затем if(!file.exists()){}, и если файл не существует, я создаю config1 (как вы мне показали) и помещаю его в map, а затем создаю и сохраняю файл. - person Oliver; 21.06.2020

Вот как вы создаете несколько объектов в одном объекте JSON:

//Creating first Object
JSONObject config1 = new JSONObject();
try {
    json.put("component1", "url");
    json.put("component2", "url");
    json.put("component2", "url");
    }
catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

//Creating second object
JSONObject config2 = new JSONObject();
try {
    json.put("component1", "url");
    json.put("component2", "url");
    json.put("component2", "url");
    }
catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

JSONObject finalJSON = new JSONObject();
try {
    //Adding both objects in one single object
    json.put("config1", config1);
    json.put("config2", config2);

    String jsonString = finalJSON.toString();

    FileOutputStream fos = this.openFileOutput("jsonfile", Context.MODE_PRIVATE);
    fos.write(jsonString.getBytes());
    fos.close();

    Log.d("JSON" , json.toString());

} catch (IOException | JSONException e) {
    e.printStackTrace();
}

Это даст вам желаемый результат. Кроме того, если вы хотите сделать какой-либо объект массивом, вы можете использовать для этого JSONArray.

person Lalit Fauzdar    schedule 19.06.2020

Рассмотрите возможность использования https://github.com/google/gson. Вы будете работать с экземпляром класса, а не с JSONObject. Гораздо удобнее.

Просто чтобы дать вам представление о том, что вы можете сделать:

public class TestClass {
    private final Map<String, String> config1;
    private final Map<String, String> config2;

    public TestClass(Map<String, String> config1, Map<String, String> config2) {
        this.config1 = config1;
        this.config2 = config2;
    }
}

        Gson gson = new GsonBuilder().setPrettyPrinting().create();

        Map<String, String> config1 = new HashMap<String, String>();
        config1.put("hello1.1", "world1.1");
        config1.put("hello1.2", "world1.2");

        Map<String, String> config2 = new HashMap<String, String>();
        config2.put("hello2.1", "world2.1");
        config2.put("hello2.2", "world2.2");

        TestClass testClass = new TestClass(config1, config2);

        Log.d("zzz", gson.toJson(testClass));

Вышеуказанные отпечатки:

    {
      "config1": {
        "hello1.1": "world1.1",
        "hello1.2": "world1.2"
      },
      "config2": {
        "hello2.1": "world2.1",
        "hello2.2": "world2.2"
      }
    }

Вы можете вернуться и принудительно установить между строкой json и самим объектом. Для редактирования вам нужно работать только с объектом - естественным и удобным способом.

person ror    schedule 19.06.2020