84.3 JSON 파일 쓰기

이번에는 parson을 사용하여 JSON 문서를 생성하고 파일에 써보겠습니다.

다음은 JSON 문서 생성에 사용할 parson의 함수입니다.

  • JSON_Value * json_value_init_object(void)
    • JSON_Value 생성 및 초기화 함수
  • JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string)
    • JSON 객체에 키를 추가하고 문자열을 저장하는 함수
  • JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number)
    • JSON 객체에 키를 추가하고 숫자를 저장하는 함수
  • JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean)
    • JSON 객체에 키를 추가하고 불 값을 저장하는 함수
  • JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value)
    • JSON 객체에 키를 추가하고 JSON_Value를 저장하는 함수
  • JSON_Value * json_value_init_array(void)
    • JSON 배열을 생성하는 함수
  • JSON_Status json_array_append_string(JSON_Array *array, const char *string)
    • JSON 배열에 문자열 요소를 추가하는 함수
  • JSON_Status json_serialize_to_file_pretty(const JSON_Value *value, const char *filename)
    • JSON_Value를 사람이 읽기 쉬운 문자열(pretty)로 만든 뒤 파일에 저장하는 함수

다음과 같이 parson 함수를 사용하여 초기화, 사용, 해제의 순서로 JSON 파일을 쓰게 됩니다.

그림 84‑10 parson 함수로 JSON 파일 쓰기

먼저 json_value_init_object 함수를 사용하여 JSON_Value를 생성하고 초기화합니다. 그리고 생성한 JSON_Value에서 json_value_get_object 함수로 JSON_Object를 얻습니다.

int main()
{
    JSON_Value *rootValue;
    JSON_Object *rootObject;

    /* 초기화 */
    rootValue = json_value_init_object();             // JSON_Value 생성 및 초기화
    rootObject = json_value_get_object(rootValue);    // JSON_Value에서 JSON_Object를 얻음

이렇게 하면 빈 객체 { }가 생성되고, 키를 추가할 수 있는 상태가 됩니다.

이제 json_object_set_string 함수를 사용하여 객체에 키를 추가하고 문자열을 저장합니다. 마찬가지로 json_object_set_number 함수를 사용하여 객체에 키를 추가하고 숫자를 저장합니다.

    /* 사용 */
    // 객체에 키를 추가하고 문자열 저장
    json_object_set_string(rootObject, "Title", "Inception");
    
    // 객체에 키를 추가하고 숫자 저장
    json_object_set_number(rootObject, "Year", 2010);
    json_object_set_number(rootObject, "Runtime", 148);
    
    // 객체에 키를 추가하고 문자열 저장
    json_object_set_string(rootObject, "Genre", "Sci-Fi");
    json_object_set_string(rootObject, "Director", "Christopher Nolan");

배열은 json_value_init_array 함수로 배열값(JSON_Value)을 생성한 뒤 json_object_set_value 함수에 넣어서 생성합니다. 단, 이 상태에서는 요소를 추가할 수 없으므로 json_object_get_array 함수로 객체에서 배열 포인터를 가져온 뒤 json_array_append_string 함수로 문자열 요소를 추가하면 됩니다.

    // 객체에 키를 추가하고 배열 생성
    json_object_set_value(rootObject, "Actors", json_value_init_array());
    
    // 객체에서 배열 포인터를 가져옴
    JSON_Array *actors = json_object_get_array(rootObject, "Actors");
    
    // 배열에 문자열 요소 추가
    json_array_append_string(actors, "Leonardo DiCaprio");
    json_array_append_string(actors, "Joseph Gordon-Levitt");
    json_array_append_string(actors, "Ellen Page");
    json_array_append_string(actors, "Tom Hardy");
    json_array_append_string(actors, "Ken Watanabe");

객체에 불 값을 저장할 때는 json_object_set_boolean 함수를 사용하면 됩니다.

    // 객체에 키를 추가하고 숫자 저장
    json_object_set_number(rootObject, "imdbRating", 8.8);
    
    // 객체에 키를 추가하고 불 값 저장
    json_object_set_boolean(rootObject, "KoreaRelease", true);

모든 객체 추가가 끝났으면 json_serialize_to_file_pretty 함수를 사용하여 JSON_Value를 사람이 읽기 쉬운 문자열로 만든 뒤 파일에 저장하면 됩니다. 만약 pretty가 붙지 않은 json_serialize_to_file 함수를 사용하면 JSON 문서에 공백과 개행이 포함되지 않고 객체와 값들이 일렬로 쭉 나열됩니다.

    // JSON_Value를 사람이 읽기 쉬운 문자열(pretty)로 만든 뒤 파일에 저장
    json_serialize_to_file_pretty(rootValue, "example.json");

마지막으로 json_value_free 함수를 사용하여 동적 메모리를 해제합니다.

    /* 해제 */
    json_value_free(rootValue);    // JSON_Value에 할당된 동적 메모리 해제

    return 0;
}

다음은 전체 소스 코드입니다(파일은 GitHub 저장소의 Unit 84/84.3/parson/parson 폴더에 들어있습니다).

main.c

#include <stdio.h>
#include <stdbool.h>    // bool, true, false가 정의된 헤더 파일
#include "parson.h"     // parson.h 헤더 파일 포함

int main()
{
    JSON_Value *rootValue;
    JSON_Object *rootObject;

    rootValue = json_value_init_object();             // JSON_Value 생성 및 초기화
    rootObject = json_value_get_object(rootValue);    // JSON_Value에서 JSON_Object를 얻음

    // 객체에 키를 추가하고 문자열 저장
    json_object_set_string(rootObject, "Title", "Inception");
    // 객체에 키를 추가하고 숫자 저장
    json_object_set_number(rootObject, "Year", 2010);
    json_object_set_number(rootObject, "Runtime", 148);
    // 객체에 키를 추가하고 문자열 저장
    json_object_set_string(rootObject, "Genre", "Sci-Fi");
    json_object_set_string(rootObject, "Director", "Christopher Nolan");

    // 객체에 키를 추가하고 배열 생성
    json_object_set_value(rootObject, "Actors", json_value_init_array());
    // 객체에서 배열 포인터를 가져옴
    JSON_Array *actors = json_object_get_array(rootObject, "Actors");
    // 배열에 문자열 요소 추가
    json_array_append_string(actors, "Leonardo DiCaprio");
    json_array_append_string(actors, "Joseph Gordon-Levitt");
    json_array_append_string(actors, "Ellen Page");
    json_array_append_string(actors, "Tom Hardy");
    json_array_append_string(actors, "Ken Watanabe");

    // 객체에 키를 추가하고 숫자 저장
    json_object_set_number(rootObject, "imdbRating", 8.8);
    // 객체에 키를 추가하고 불 값 저장
    json_object_set_boolean(rootObject, "KoreaRelease", true);

    // JSON_Value를 사람이 읽기 쉬운 문자열(pretty)로 만든 뒤 파일에 저장
    json_serialize_to_file_pretty(rootValue, "example.json");

    json_value_free(rootValue);    // JSON_Value에 할당된 동적 메모리 해제

    return 0;
}

Visual Studio에서 Ctrl+F5 키를 눌러서 프로그램을 실행하면 .c 파일이 있는 폴더에 다음과 같은 내용으로 example.json 파일이 생성됩니다.

example.json

{
    "Title": "Inception",
    "Year": 2010,
    "Runtime": 148,
    "Genre": "Sci-Fi",
    "Director": "Christopher Nolan",
    "Actors": [
        "Leonardo DiCaprio",
        "Joseph Gordon-Levitt",
        "Ellen Page",
        "Tom Hardy",
        "Ken Watanabe"
    ],
    "imdbRating": 8.800000,
    "KoreaRelease": true
}

지금까지 GitHub의 소스 코드를 사용하는 방법을 알아보았습니다. 실무에서는 모든 기능을 구현하기 보다는 이미 있는 소스 코드를 활용하는 경우가 많습니다. 따라서 프로젝트에 파일 추가하기, 헤더 파일 포함하기, 함수 호출하기 부분을 정확히 익히는 것이 좋습니다.