Как сделать запись в json файл?
Как реализовать запись в файл? У меня в assets есть json файл и чтение с него происходит хорошо, а вот запись как делать нигде не могу найти. Вот код:
binding.apply < buton.setOnClickListener < write_sjon() read_json() for (i in 0..arr.size - 1) < if ((edittext1.text.toString() == arr[i]) and (edittext2.text.toString() == arr[i + 1])) < Toast.makeText(this@MainActivity, "OK", Toast.LENGTH_LONG).show() break >if (i == 6) break > > > > fun read_json() < var json: String? = null try < val inputStream: InputStream = assets.open("login.json") json = inputStream.bufferedReader().use < it.readText() >val jsonar = JSONArray(json) for (i in 0..jsonar.length() - 1) < val jsonobj = jsonar.getJSONObject(i) arr.add(jsonobj.getString("login")) arr.add(jsonobj.getString("password")) >> catch (e: Exception) < Log.e("Exception", "Json file not find") >>
В конце еще есть метод
fun write_sjon() <>
В него-то мне и надо добавить возможность записи в файл,желателен простой пример для понимания на примере логин:пароль
JSoN файл: [ < "login": "Pimp", "password": "123" >, < "login": "Lops", "password": "443" >, < "login": "Hos", "password": "295" >, < "login": "Kok", "password": "728" >]
Чтение и запись в файл JSON-объекта
Эта статья научит вас парсить данные из JSON. Также вы узнаете, как читать и записывать в файл данные JSON.
За последние 5-10 лет формат JSON был одним из самых популярных способов сериализации данных (если не самым популярным). Особенно в веб-разработке. С этим форматом вы столкнетесь при работе с REST API, конфигурациями приложений или базами данных.
Несомненно, знать принципы работы JSON — очень важно. В какой-то момент вы обязательно с ним встретитесь. Возможно, вы захотите узнать, как читать и записывать JSON в файл. Все эти действия — очень простые. В этом вы убедитесь, разобрав следующие примеры.
Запись JSON в файл
Самый простой способ записать JSON в файл — использовать словарь. Они могут хранить вложенные словари, массивы, булевы значения и другие типы данных вроде целых чисел и строк. Более детальный список поддерживаемых типов данных можно найти здесь.
Во встроенной библиотеке json есть «волшебный» метод, который позволяет конвертировать словари в сериализованную JSON-строку.
import json data = <> data['people'] = [] data['people'].append(< 'name': 'Scott', 'website': 'pythonist.ru', 'from': 'Nebraska' >) data['people'].append(< 'name': 'Larry', 'website': 'pythonist.ru', 'from': 'Michigan' >) data['people'].append(< 'name': 'Tim', 'website': 'pythonist.ru', 'from': 'Alabama' >) with open('data.txt', 'w') as outfile: json.dump(data, outfile)
После импорта библиотеки json мы объявляем несколько словарей и наполняем их данными. Самая важная часть — в конце программы. Здесь мы используем оператор with , чтобы открыть файл. После этого мы используем метод json.dump , чтобы записать наши словари в файл.
Вторым аргументом может быть любой файлоподобный объект — даже если это не совсем файл. Например, сокет. Его можно открыть, закрыть и записать так же, как и файл. С подобным вариантом использования JSON вы точно столкнетесь — это важно запомнить.
Стоит упомянуть и о вариации метода json.dump — json.dumps . Этот метод позволяет вернуть JSON-строку, а не записывать ее в файл. Это может быть полезно, если вы хотите изменить JSON-строку. (например, зашифровать)
Чтение JSON из файла
Чтение JSON из файла такое же простое, как и запись. С помощью библиотеки json мы можем спарсить JSON-строку прямо из файла. В этом примере мы парсим данные и выводим их в консоль:
import json with open('data.txt') as json_file: data = json.load(json_file) for p in data['people']: print('Name: ' + p['name']) print('Website: ' + p['website']) print('From: ' + p['from']) print('')
json.load — очень важный метод, запомните его. С его помощью происходит чтение файла, парс JSON-данных. После этого все данные записываются в словарь и возвращаются вам.
Как и у json.dump , у json.load есть дополнительный метод. Он позволяет работать со строками напрямую, ведь чаще всего у вас не будет файлоподобного объекта, содержащего JSON. Как вы уже догадались, называется он json.loads . Допустим, вы вызываете конечную точку REST с помощью GET, который возвращает строку. Ее мы и можем напрямую передать в json.loads .
Параметры
При сериализации данных в JSON могут возникнуть проблемы. Например, его будет не очень удобно читать, ведь удаляются все пробелы. В большинстве случаев этот вариант вполне хорош, но порой нужно внести небольшие изменения. К примеру, добавить пробелы, чтобы JSON было удобнее читать. У json.load и json.dump есть несколько параметров, которые дают необходимую гибкость. О некоторых из них мы и поговорим.
Pretty-Printing
Сделать JSON более удобочитаемым (pretty-printing) — очень просто. Нужно лишь передать целое число в параметр indent :
import json data = <'people':[<'name': 'Scott', 'website': 'pythonist.ru', 'from': 'Nebraska'>]> json.dumps(data, indent=4) < "people": [ < "website": "pythonist.ru", "from": "Nebraska", "name": "Scott" >] >
Это довольно полезно. Особенно если вам часто приходится читать JSON во время работы. Также вы можете использовать использовать команду json.tool прямо в командной строке. Если вы хотите удобочитаемый JSON, наберите в командной строке следующий код:
$ echo '<"people":[<"name":"Scott", "website":"pythonist.ru", "from":"Nebraska">]>' | python -m json.tool < "people": [ < "name": "Scott", "website": "pythonist.ru" "from": "Nebraska", >] >
Сортировка
В JSON объект определяется следующим образом:
Объект — это неупорядоченный набор пар ключ/значение.
То есть, порядок не гарантируется. Но навести его реально. Сделать это можно с помощью передачи True в параметр sort_keys в методах json.dump или json.dumps .
import json data = <'people':[<'name': 'Scott', 'website': 'pythonist.ru', 'from': 'Nebraska'>]> json.dumps(data, sort_keys=True, indent=4) < "people": [ < "from": "Nebraska", "name": "Scott", "website": "pythonist.ru" >] >
ASCII-текст
По умолчанию json.dump проверяет, имеет ли ваш текст в словаре кодировку ASCII. Если присутствуют символы, отличные от ASCII, они автоматически экранируются. Это показано в следующем примере:
import json data = jstr = json.dumps(data, indent=4) print(jstr)
Но это не всегда приемлемо. Во многих случаях вы бы хотели сохранить символы Unicode нетронутыми. Для этого нужно передать в параметр ensure_ascii значение False .
jstr = json.dumps(data, ensure_ascii=False, indent=4) print(jstr)
Записать в файл JSON
Выходной коннектор Записать в файл JSON может использоваться для записи событий GeoEvent, интерпретированных как универсальный файл JSON, в файл JSON.
Примечания по использованию
- Этот выходной коннектор связывает исходящий адаптер универсального файла JSON с исходящим транспортом файла.
- Зарегистрированная папка сервера может быть задана с помощью абсолютного или относительного пути.
- Если используется относительный путь, учетной записи службы Windows, под которой запущен GeoEvent Server , требуется разрешение на чтение/запись в папку.
- Рекомендуется использовать абсолютные пути, например, C:\GeoEvent\input для свойства Папка .
- Свойство Подпапка позволяет указать подпапку, связанную с зарегистрированной папкой сервера.
- При перезапуске выхода GeoEvent Server создаст новый файл в зарегистрированной системной папке.
- В зависимости от скорости и объема обрабатываемых событий GeoEvent рекомендуется увеличить Размер перехода к следующему файлу (КБ) на значение больше значения по умолчанию 1 , чтобы избежать создания каскада файлов JSON, с которыми Windows не сможет справиться.
- Этот выходной коннектор представляет каждую запись события как отдельный объект JSON в файле JSON. С установленными по умолчанию Верхним колонтитулом файла , Нижним колонтитулом файла и Разделителем событий , каждый объект JSON организуется в корректный массив JSON с элементами, разделенными запятой. Открывающая квадратная скобка Верхнего колонтитула файла определяет начало массива JSON, а закрывающая квадратная скобка Нижнего колонтитула файла определяет конец массива JSON. Запятая Разделителя событий разделяет каждый объект JSON.
Параметры
Описательное имя выходного коннектора, используемое для справки в GeoEvent Manager.
Зарегистрированная системная папка, под которой будут создаваться и записываться файлы.
Префикс имени файла
Задает имя выходного файла, который GeoEvent Server будет создавать и в который будут записываться данные. К имени файла добавляется дата / время первого создания файла. По умолчанию – output .
Пример: префикс имени файла output , созданного 19 марта 2019 года в 2:30:05 pm, в результирующем имени файла будет output2019-03-19_14-30-05.out .
Указывает имя подпапки (или подкаталога) относительно зарегистрированной системной папки, под которой будут создаваться и записываться файлы. Это свойство следует оставить пустым, если вложенная папка не существует. Для этого свойства отсутствует значение по умолчанию.
Пример: при указании зарегистрированной системной папки как C:\GeoEvent и подпапок как output GeoEvent Server создаст свой файл в C:\GeoEvent\output предполагая, что путь к файлу существует и доступен учетной записью службы Windows, запускающей ArcGIS GeoEvent Server .
Расширение файла, используемое при создании новых файлов. По умолчанию для этого свойства используется json , что означает, что GeoEvent Server создаст файл JSON.
Метод перехода к следующему файлу
- По размеру – GeoEvent Server прекратит запись в текущий файл при достижении заданного порогового значения размера файла. При достижении порогового значения будет создан новый файл.
- По времени – GeoEvent Server прекратит запись в текущий файл при достижении заданного порогового значения времени. При достижении порогового значения будет создан новый файл.
Размер перехода к следующему файлу (КБ)
Задает максимальный размер файла в килобайтах (КБ), который может быть достигнут до того, как GeoEvent Server прекратит запись. После того как максимальный размер файла достигнут, GeoEvent Server создаст новый файл, и продолжит запись в него. По умолчанию – 1 килобайт.
Это свойство показывается, когда для свойства Метод перехода к следующему файлу задано значение По размеру , и скрыто, если выбрано значение По времени
Частота перехода к следующему файлу
- Каждый день – GeoEvent Server прекратит запись в текущий файл и начнет запись в новый файл каждый час.
- Каждый день – GeoEvent Server прекратит запись в текущий файл и начнет запись в новый файл каждый день.
- Каждый месяц – GeoEvent Server прекратит запись в текущий файл и начнет запись в новый файл каждый месяц.
Это свойство показывается, когда для свойства Метод перехода к следующему файлу задано значение По времени , и скрыто, если выбрано значение По размеру
Возраст очистки файлов (минуты)
Указывает возраст в минутах, с которого старые файлы будут обрабатываться в соответствии с Методом очистки файлов . По умолчанию – 4320 минут.
Пример: каждые 3 дня (4320 минут) файлы будут либо удалены или помещены в архив.
Метод очистки файлов
- Удалить – файл, достигший возраста, указанного в свойстве Возраст очистки файла (минуты) будет удален.
- Архивировать – файл, достигший возраста, указанного в свойстве Возраст очистки файла (минуты) будет помещен в архив.
Зарегистрированная системная папка, под которой будут архивироваться файлы, достигшие возраста очистки файлов (минуты) . Для этого свойства отсутствует значение по умолчанию.
Это свойство показывается, когда для Метода очистки файлов задано значение Архивировать , и скрыто, если выбрано значение Удалить
Подпапка относительно Папки архива , под которой будут архивироваться файлы, достигшие возраста очистки файлов (минуты) . Оставьте это свойство неуказанным, если подпапка для архивирования файлов отсутствует. Для этого свойства отсутствует значение по умолчанию.
Это свойство показывается, когда для Метода очистки файлов задано значение Архивировать , и скрыто, если выбрано значение Удалить
- Да – исходный JSON будет форматироваться (подготавливаться).
- Нет – исходный JSON не будет форматироваться.
Верхний колонтитул файла
Символ(ы), который будет вставлен в начале каждого файла JSON. GeoEvent Server может использовать любой обычный символ ASCII или комбинацию символов в качестве верхнего колонтитула файла. По умолчанию – [ (левая скобка).
Нижний колонтитул файла
Символ(ы), который будет вставлен в конце каждого файла JSON. GeoEvent Server может использовать любой обычный символ ASCII или комбинацию символов в качестве нижнего колонтитула файла. По умолчанию – ] (правая скобка).
Символ, который будет использоваться для разделения каждой записи события в файле JSON. GeoEvent Server может применять любой обычный символ ASCII в качестве разделителя событий. По умолчанию – , (запятая).
В этом разделе
- Примечания по использованию
- Параметры
Запись данных в формате JSON
В одной из моих программ понадобилась запись данных в формате JSON. Вкратце — XML-подобный формат, вполне подходит на замену Windows INI-файлам или тому же XML. Удобен тем, что поддерживает массивы и вложенность собственных структур, но при этом не замусоривает файл данных своими тегами до полной нечитабельности человеком. Вот пример файла данных:
< "Comment":"My comment", "Count":10, "DiskParam": < "DB":10.000000, "DBAngle":1.234000 >, "Range":true, "Blades": [ < "Caption":"A", "Value":65 >, < "Caption":"B", "Value":66 >, < "Caption":"C", "Value":67 >], "Slots": [ 0,1,2 ] >
Формат довольно простой, вполне можно работать с ним без всяких библиотек. Поэтому первоначально за запись отвечал примерно такой участок кода:
fprintf(pOut, "<\n"); fprintf(pOut, " \"Comment\":\"%s\"", Header->Comment); fprintf(pOut, ",\n \"NumSt\":%d", Header->NumSt); //Пропущено немного кода fprintf(pOut, ",\n \"DBMax\":%lf", Header->DBMax); fprintf(pOut, ",\n \"Range\":%s", Header->Range?"true":"false"); fprintf(pOut, ",\n \"Blades\":\n ["); for(int i=0; iCount; i++) < TElement &e=Element[i]; fprintf(pOut, i?",\n "); > fprintf(pOut, "\n ]"); //Пропущено много кода fprintf(pOut, "\n>");
Корявенько, хотя вполне работоспособно. Но программа активно дорабатывалась, формат данных менялся по 5 раз на дню и остро встала проблема отслеживания всех изменений. Несмотря на некоторое форматирование исходника было тяжело не забыть закрыть какой-нибудь тег или правильно напечатать нужное число пробелов для форматирования уже собственно файла данных. Даже в приведенном фрагменте перед публикацией обнаружилась ошибка, не ставилась запятая между элементами массива.
Решил я этот техпроцесс слегка механизировать и создать микробиблиотеку для работы с JSON.
Что я хотел? Чтобы в своей программе я писал что-то на псевдоязыке:
Key("Ключ1"); Value("Значение1"); Key("Ключ2"); Value("Значение2"); Object("Объект1"); Key("Ключ3"); Value("Значение3"); //Ключ3,Ключ4 являются элементами Объект1 Key("Ключ4"); Value("Значение4"); Array("Массив1"); Key("Ключ5"); Value("Значение5"); //Ключ5. КлючN являются элементами Массив1 Key("Ключ6"); Value("Значение6"); . Key("КлючN"); Value("ЗначениеN");
А компилятор/программа пусть сами учтут отступы, которые определяют структуру файла данных. В нужный момент подставят открывающий и, главное, закрывающий тег. Дело осложнялось тем, что внутри этого скрипта хотелось использовать конструкции C++, например циклы внутри массивов.
После нескольких дней непрерывной мозговой осады этой проблемы нашлось довольно изящное решение. Для контроля за вложением друг в друга JSON-сущностей и своевременного закрытия тегов используется область видимости переменных. Все очень просто, создается экземпляр одного из классов TJson*** — записывается ключ и открывающий тег и все следующие созданные объекты считаются его вложениями. Уничтожается экземпляр — ставится закрывающий тег.
#define TCF_USED 1 class TTagCloser < public: TTagCloser *Owner; static TTagCloser *Current; static int Depth; int Flags; int Count; int operator()()TTagCloser() ~TTagCloser() >; TTagCloser *TTagCloser::Current=NULL; int TTagCloser::Depth=-1;
Простой класс, все назначение которого — временно связать порожденные объекты в некое подобие дерева. Для чего нужен перегруженный operator() будет понятно чуть позже.
У этого класса есть наследник, в котором заложен базовый функционал записи в JSON-формате. Программист должен только переопределить функции Write***.
#define TCF_OBJECT 4 #define TCF_ARRAY 2 class TJsonTagCloser:public TTagCloser < public: void WriteTab(); void WriteInt(int); void WriteDouble(double); void WriteStr(char *); TJsonTagCloser(char *Key); >; //---------------------------------------------------------------------------- TJsonTagCloser::TJsonTagCloser(char *Key):TTagCloser() < if(Owner) < if(Owner->Count) WriteStr(","); if(Owner->Flags&TCF_ARRAY) < if(!Owner->Count) WriteTab(); > else < WriteTab(); WriteStr("\""); if(Key) WriteStr(Key); WriteStr("\":"); >Owner->Count++; > >
Функция WriteTab() введена в программу удобства гиков, любящих лазить в файлы данных «Блокнотом». Она должна записать в файл данных перевод строки и число пробелов, соответствующее глубине вложения (TTagCloser::Depth). Если бы форматирование не было нужно, то функция выродилась бы в WriteTab().
У меня в тестовом примере функции Write*** определены так:
#include void TJsonTagCloser::WriteTab()void TJsonTagCloser::WriteInt(int Value) void TJsonTagCloser::WriteDouble(double Value) void TJsonTagCloser::WriteStr(char *Value)
JSON-формат предполагает наличие в потоке данных Объектов (смахивают на СИшные структуры), Массивов (они и в Африке массивы) и просто пар «Ключ: Значение». Все это многообразие может быть перемешано и вложено друг в дружку, например в паре «Ключ: Значение» Значением может быть Массив Объектов. Для работы с этими сущностями созданы следующие классы:
class TJsonArray:public TJsonTagCloser < public: TJsonArray(char *Key); ~TJsonArray(); >; class TJsonObject:public TJsonTagCloser < public: TJsonObject(char *Key); ~TJsonObject(); >; class TJsonValue:public TJsonTagCloser < public: TJsonValue(char *Key, int Value):TJsonTagCloser(Key)TJsonValue(char *Key, double Value):TJsonTagCloser(Key) TJsonValue(char *Key, bool Value):TJsonTagCloser(Key) TJsonValue(char *Key, char *Value); >; TJsonArray::TJsonArray(char *Key):TJsonTagCloser(Key) < Flags|=TCF_ARRAY; if(Owner && (!(Owner->Flags&TCF_ARRAY) || Owner->Count>1)) WriteTab(); WriteStr("["); > TJsonArray::~TJsonArray() < WriteTab(); WriteStr("]"); >//---------------------------------------------------------------------------- TJsonObject::TJsonObject(char *Key):TJsonTagCloser(Key) < Flags|=TCF_OBJECT; if(Owner && (!(Owner->Flags&TCF_ARRAY) || Owner->Count>1)) WriteTab(); WriteStr(" <"); >TJsonObject::~TJsonObject() < WriteTab(); WriteStr(">"); > TJsonValue::TJsonValue(char *Key, char *Value):TJsonTagCloser(Key) < if(Value) < WriteStr("\""); WriteStr(Value); WriteStr("\""); >else WriteStr("null"); >
Для удобства использования библиотеки в своей программе определены макросы:
#define ARRAY(k) for(TJsonArray array(k); array();) #define OBJECT(k) for(TJsonObject object(k); object();) #define VALUE(k,v)
Вот и добрались до перегруженного operator(). Он нужен для однократного выполнения тела цикла for, то есть в первый вызов он возвращает true, а в последующие — false.
А вот так в теле программы выглядит скрипт, на котором пишется заполнение файла данных:
void main() < OBJECT("") < VALUE("Comment", "My comment"); VALUE("Count", 10); OBJECT("DiskParam") < VALUE("DB", 10.0); VALUE("DBAngle", 1.234); >VALUE("Range", true); ARRAY("Blades") < for(int i='A'; i> ARRAY("Slots") for(int i=0; i >
Как выглядит сформированный этой программой JSON-файл можно посмотреть в начале статьи. Все запятые проставлены, все скобочки закрыты когда нужно, в каждой строке нужное количество ведущих пробелов — красота!