C언어에서 스트림을 사용한 JSON 파일 읽기와 쓰기

C언어에서 JSON 파일을 읽고 쓰는 것은 데이터 저장과 교환을 위한 중요한 기술입니다. 많은 현대 애플리케이션에서는 JSON 형식을 사용하여 데이터를 저장하고 전달합니다. C언어는 기본적으로 JSON 파싱을 지원하지 않지만, 스트림을 활용하여 파일을 읽고 쓸 수 있습니다. 이 기사에서는 C언어의 스트림 기능을 이용하여 JSON 파일을 효율적으로 처리하는 방법을 설명합니다.

JSON 파일 형식 이해


JSON(JavaScript Object Notation)은 데이터 저장 및 교환을 위한 텍스트 기반의 형식입니다. 사람이 읽을 수 있고 기계가 쉽게 파싱할 수 있는 형태로 데이터를 표현하는 데 사용됩니다. JSON은 데이터 구조를 객체와 배열로 표현하며, 일반적으로 다음과 같은 형식을 따릅니다:

JSON 구조


JSON 데이터는 두 가지 기본 구조로 이루어집니다.

  • 객체 (Object): 중괄호 {}로 감싸지며, “키-값” 쌍으로 데이터를 표현합니다.
  • 배열 (Array): 대괄호 []로 감싸지며, 순서가 있는 데이터 목록을 표현합니다.

예시

{
  "name": "John Doe",
  "age": 30,
  "isStudent": false,
  "courses": ["Math", "Physics", "Computer Science"]
}

C언어에서 JSON 처리


C언어는 JSON 데이터를 기본적으로 지원하지 않으므로, 외부 라이브러리를 활용하여 JSON 파일을 처리해야 합니다. 이 기사에서는 JSON 파일을 읽고 쓸 때 사용되는 주요 함수와 방법들을 소개합니다. C언어에서 JSON을 읽고 쓰는 과정은 파일 입출력 스트림을 활용하여 데이터를 처리하는 방식으로 진행됩니다.

C언어에서 파일 입출력 스트림 사용


C언어에서 파일을 읽고 쓰는 작업은 주로 파일 입출력 스트림을 통해 이루어집니다. C언어의 표준 라이브러리에는 파일 처리와 관련된 다양한 함수가 포함되어 있으며, 이를 이용하여 파일을 열고, 데이터를 읽고, 작성한 후 파일을 닫을 수 있습니다.

파일 열기와 닫기


파일을 다루기 위해서는 먼저 파일을 열어야 하며, 작업이 끝난 후에는 파일을 닫아야 합니다. C언어에서는 fopen() 함수로 파일을 열고, fclose() 함수로 파일을 닫습니다.

예시

FILE *file = fopen("data.json", "r"); // 파일 열기 (읽기 모드)
if (file == NULL) {
    printf("파일을 열 수 없습니다.\n");
    return 1;
}
fclose(file); // 파일 닫기

파일에서 데이터 읽기


파일에서 데이터를 읽을 때는 fread() 또는 fgets()와 같은 함수를 사용합니다. fread()는 바이너리 데이터를, fgets()는 텍스트 데이터를 한 줄씩 읽을 때 사용됩니다.

예시

char buffer[100];
FILE *file = fopen("data.json", "r");
if (file != NULL) {
    while (fgets(buffer, sizeof(buffer), file)) {
        printf("%s", buffer); // 파일에서 한 줄씩 읽어 출력
    }
    fclose(file);
}

파일에 데이터 쓰기


파일에 데이터를 쓸 때는 fwrite()fprintf()를 사용할 수 있습니다. fwrite()는 바이너리 데이터를, fprintf()는 텍스트 데이터를 포맷에 맞춰 출력하는 데 사용됩니다.

예시

FILE *file = fopen("data.json", "w"); // 파일 열기 (쓰기 모드)
if (file != NULL) {
    fprintf(file, "{\"name\":\"John Doe\", \"age\":30}"); // JSON 형식으로 텍스트 쓰기
    fclose(file);
}

스트림 처리의 주의사항


파일 입출력 스트림을 사용할 때는 항상 파일이 성공적으로 열렸는지 확인하고, 작업이 끝난 후 파일을 반드시 닫아야 합니다. 또한, 파일을 읽거나 쓸 때 발생할 수 있는 오류를 처리하기 위해 적절한 예외 처리를 하는 것이 중요합니다.

JSON 파일 읽기 위한 스트림 사용법


C언어에서 JSON 파일을 읽으려면, 먼저 파일을 열고 스트림을 사용하여 데이터를 읽은 후 JSON 구조를 분석하는 과정이 필요합니다. JSON 데이터는 텍스트 형식으로 저장되므로, 이를 처리하려면 텍스트 파일 읽기 함수들을 적절히 사용해야 합니다.

파일 열기


파일을 읽기 위해서는 fopen() 함수를 사용하여 JSON 파일을 열어야 합니다. 이때 "r" 모드를 사용하여 읽기 전용으로 파일을 엽니다.

예시

FILE *file = fopen("data.json", "r");
if (file == NULL) {
    printf("파일을 열 수 없습니다.\n");
    return 1;
}

파일에서 JSON 데이터 읽기


파일을 읽을 때는 fgets()fread() 함수를 사용하여 JSON 데이터를 메모리로 불러옵니다. fgets()는 파일에서 한 줄씩 읽는 데 유용하고, fread()는 지정한 크기만큼 데이터를 한 번에 읽을 때 사용됩니다. 읽은 데이터를 문자열로 처리한 후, 이를 파싱하는 방법을 사용합니다.

예시: `fgets()` 사용

char buffer[256];
while (fgets(buffer, sizeof(buffer), file)) {
    printf("읽은 데이터: %s", buffer); // 파일에서 한 줄씩 읽어 출력
}

JSON 파싱을 위한 라이브러리 사용


C언어에서는 기본적으로 JSON 파일을 파싱하는 기능이 없으므로 외부 라이브러리를 사용해야 합니다. jansson이나 cJSON과 같은 라이브러리를 사용하면 JSON 데이터를 쉽게 파싱할 수 있습니다. 이들 라이브러리는 JSON 텍스트를 객체로 변환하고, 데이터를 쉽게 접근할 수 있는 API를 제공합니다.

예시: `cJSON` 라이브러리 사용

#include <stdio.h>
#include <stdlib.h>
#include <cjson/cJSON.h>

FILE *file = fopen("data.json", "r");
if (file == NULL) {
    printf("파일을 열 수 없습니다.\n");
    return 1;
}

char buffer[256];
fgets(buffer, sizeof(buffer), file);  // JSON 파일의 첫 줄을 읽음
fclose(file);

cJSON *json = cJSON_Parse(buffer);  // JSON 텍스트 파싱
if (json == NULL) {
    printf("JSON 파싱 오류\n");
    return 1;
}

// JSON 데이터에서 값 추출
cJSON *name = cJSON_GetObjectItem(json, "name");
if (cJSON_IsString(name) && (name->valuestring != NULL)) {
    printf("이름: %s\n", name->valuestring);
}

cJSON_Delete(json);  // 메모리 해제

파일 포인터와 메모리 관리


파일에서 데이터를 읽은 후에는 반드시 fclose()를 호출하여 파일을 닫고, cJSON_Delete() 같은 함수로 JSON 객체의 메모리를 해제해야 합니다. 파일을 제대로 닫지 않으면 메모리 누수나 데이터 손상이 발생할 수 있습니다.

JSON 파싱을 위한 라이브러리 사용


C언어는 기본적으로 JSON 파싱 기능을 제공하지 않으므로, 외부 라이브러리를 활용하여 JSON 데이터를 쉽게 처리할 수 있습니다. 대표적인 JSON 파싱 라이브러리로는 janssoncJSON이 있습니다. 이들 라이브러리를 사용하면 JSON 문자열을 객체로 변환하고, 객체에서 필요한 데이터를 추출하거나 수정할 수 있습니다.

jansson 라이브러리


jansson은 C언어에서 JSON 데이터를 처리하기 위한 인기 있는 라이브러리입니다. 이 라이브러리는 JSON 객체를 생성하고, 파싱하고, 수정하는 다양한 기능을 제공합니다.

jansson 설치


jansson을 설치하려면 아래와 같이 패키지를 설치할 수 있습니다.

sudo apt-get install libjansson-dev

jansson 예시

#include <stdio.h>
#include <jansson.h>

int main() {
    FILE *file = fopen("data.json", "r");
    if (file == NULL) {
        printf("파일을 열 수 없습니다.\n");
        return 1;
    }

    // 파일 내용을 읽어 JSON 문자열로 저장
    char buffer[256];
    fgets(buffer, sizeof(buffer), file);
    fclose(file);

    // JSON 문자열 파싱
    json_t *root;
    json_error_t error;
    root = json_loads(buffer, 0, &error);
    if (!root) {
        printf("JSON 파싱 오류: %s\n", error.text);
        return 1;
    }

    // JSON 객체에서 데이터 추출
    json_t *name = json_object_get(root, "name");
    if (json_is_string(name)) {
        printf("이름: %s\n", json_string_value(name));
    }

    // JSON 객체 해제
    json_decref(root);

    return 0;
}

cJSON 라이브러리


cJSON은 C언어에서 JSON을 다루기 위한 경량 라이브러리로, 간단하고 직관적인 API를 제공합니다. cJSON은 주로 JSON 객체를 파싱하고 생성하는 데 사용됩니다.

cJSON 설치


cJSON을 설치하려면 다음 명령을 사용합니다.

sudo apt-get install libcjson-dev

cJSON 예시

#include <stdio.h>
#include <stdlib.h>
#include <cjson/cJSON.h>

int main() {
    FILE *file = fopen("data.json", "r");
    if (file == NULL) {
        printf("파일을 열 수 없습니다.\n");
        return 1;
    }

    // JSON 데이터 읽기
    char buffer[256];
    fgets(buffer, sizeof(buffer), file);
    fclose(file);

    // JSON 데이터 파싱
    cJSON *json = cJSON_Parse(buffer);
    if (json == NULL) {
        printf("JSON 파싱 오류\n");
        return 1;
    }

    // JSON 객체에서 데이터 추출
    cJSON *name = cJSON_GetObjectItem(json, "name");
    if (cJSON_IsString(name) && (name->valuestring != NULL)) {
        printf("이름: %s\n", name->valuestring);
    }

    // JSON 객체 메모리 해제
    cJSON_Delete(json);

    return 0;
}

라이브러리 선택


janssoncJSON 모두 C언어에서 JSON 데이터를 파싱하고 처리하는 데 유용하지만, 각 라이브러리는 사용 목적에 따라 선택할 수 있습니다.

  • jansson: 기능이 풍부하고, 대형 프로젝트에서 안정성이 뛰어납니다.
  • cJSON: 간단하고 가벼운 라이브러리로, 성능과 메모리 사용 측면에서 유리합니다.

두 라이브러리 모두 C언어에서 JSON을 효과적으로 처리하는 데 유용한 도구입니다.

C언어에서 JSON 파일 쓰기


C언어에서 JSON 데이터를 파일에 쓰려면, 먼저 적절한 형식으로 JSON 객체를 생성한 후, 이를 텍스트 파일에 기록하는 방법을 사용합니다. fprintf()fwrite()와 같은 파일 쓰기 함수로 JSON 데이터를 파일에 저장할 수 있습니다. 이 과정에서 JSON 데이터를 직렬화하여 텍스트 형식으로 저장해야 합니다.

파일 열기


파일에 데이터를 쓰기 위해서는 fopen() 함수로 파일을 열어야 합니다. "w" 모드를 사용하면 파일을 쓰기 전용으로 열고, 파일이 없으면 새로 생성됩니다.

예시

FILE *file = fopen("data.json", "w");
if (file == NULL) {
    printf("파일을 열 수 없습니다.\n");
    return 1;
}

JSON 데이터 직렬화


C언어에서 JSON 데이터를 파일에 기록할 때는 JSON 객체를 텍스트 형식으로 직렬화해야 합니다. 이를 위해 jansson이나 cJSON 라이브러리를 사용하여 JSON 객체를 문자열로 변환합니다.

예시: `jansson`을 이용한 JSON 직렬화

#include <stdio.h>
#include <jansson.h>

int main() {
    // JSON 객체 생성
    json_t *root = json_object();
    json_object_set_new(root, "name", json_string("John Doe"));
    json_object_set_new(root, "age", json_integer(30));
    json_object_set_new(root, "isStudent", json_false());

    // 파일 열기
    FILE *file = fopen("data.json", "w");
    if (file == NULL) {
        printf("파일을 열 수 없습니다.\n");
        return 1;
    }

    // JSON 데이터를 텍스트로 직렬화하여 파일에 기록
    if (json_dumpf(root, file, JSON_INDENT(4)) != 0) {
        printf("JSON 데이터를 파일에 쓸 수 없습니다.\n");
        json_decref(root);
        fclose(file);
        return 1;
    }

    // JSON 객체 메모리 해제
    json_decref(root);
    fclose(file);

    return 0;
}

예시: `cJSON`을 이용한 JSON 직렬화

#include <stdio.h>
#include <stdlib.h>
#include <cjson/cJSON.h>

int main() {
    // JSON 객체 생성
    cJSON *root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "name", "John Doe");
    cJSON_AddNumberToObject(root, "age", 30);
    cJSON_AddBoolToObject(root, "isStudent", 0);

    // 파일 열기
    FILE *file = fopen("data.json", "w");
    if (file == NULL) {
        printf("파일을 열 수 없습니다.\n");
        return 1;
    }

    // JSON 데이터를 텍스트로 직렬화하여 파일에 기록
    char *json_string = cJSON_Print(root);
    if (json_string == NULL) {
        printf("JSON 데이터를 직렬화할 수 없습니다.\n");
        cJSON_Delete(root);
        fclose(file);
        return 1;
    }

    fprintf(file, "%s", json_string); // 파일에 기록
    free(json_string); // 메모리 해제

    // JSON 객체 메모리 해제
    cJSON_Delete(root);
    fclose(file);

    return 0;
}

파일에 JSON 쓰기 주의사항

  • 파일 열기 모드: 파일을 쓸 때 "w" 모드를 사용하면 기존 파일을 덮어쓰게 됩니다. 추가 모드로 "a"를 사용하면 기존 파일 끝에 데이터를 추가할 수 있습니다.
  • 직렬화 형식: JSON_INDENT(4)jansson에서 사용되는 옵션으로, JSON 데이터를 사람이 읽기 좋게 4칸 들여쓰기로 포맷할 수 있습니다. cJSON_Print()는 JSON 데이터를 한 줄로 출력하지만, cJSON_PrintUnformatted()를 사용하면 들여쓰기가 없는 JSON 문자열을 얻을 수 있습니다.
  • 메모리 해제: JSON 객체를 사용한 후에는 json_decref()(jansson)나 cJSON_Delete()(cJSON)를 사용하여 메모리를 해제해야 합니다.

파일 읽기 및 쓰기 성능 최적화


C언어에서 JSON 파일을 읽고 쓸 때, 파일 입출력 성능을 최적화하는 것이 중요합니다. 특히 대용량 파일을 처리할 때는 읽기와 쓰기 성능이 애플리케이션의 전체 성능에 큰 영향을 미칠 수 있습니다. 효율적인 파일 처리 방법을 사용하면 성능을 크게 향상시킬 수 있습니다.

버퍼링을 활용한 성능 향상


파일을 읽고 쓸 때는 버퍼링을 활용하여 성능을 최적화할 수 있습니다. C언어의 fread()fwrite()는 기본적으로 버퍼링을 사용하여 성능을 향상시키지만, 파일을 다룰 때 적절한 버퍼 크기를 선택하는 것이 중요합니다.

버퍼 크기 최적화 예시

#define BUFFER_SIZE 4096  // 4KB 버퍼 크기 설정

FILE *file = fopen("data.json", "r");
if (file == NULL) {
    printf("파일을 열 수 없습니다.\n");
    return 1;
}

char buffer[BUFFER_SIZE];
size_t bytesRead;
while ((bytesRead = fread(buffer, 1, BUFFER_SIZE, file)) > 0) {
    // 데이터를 읽고 처리하는 코드
}
fclose(file);

메모리 매핑을 통한 성능 향상


대용량 JSON 파일을 처리할 때, 메모리 매핑을 활용하면 성능을 더욱 최적화할 수 있습니다. 메모리 매핑은 파일을 메모리에 직접 매핑하여 파일 I/O를 수행하는 방식으로, 큰 파일을 읽고 쓸 때 성능을 극대화할 수 있습니다. mmap() 함수를 사용하면 파일을 메모리처럼 다룰 수 있습니다.

메모리 매핑 예시

#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>

int main() {
    int fd = open("data.json", O_RDONLY);
    if (fd == -1) {
        printf("파일을 열 수 없습니다.\n");
        return 1;
    }

    off_t fileSize = lseek(fd, 0, SEEK_END); // 파일 크기 구하기
    void *mappedMemory = mmap(NULL, fileSize, PROT_READ, MAP_PRIVATE, fd, 0);
    if (mappedMemory == MAP_FAILED) {
        printf("메모리 매핑 오류\n");
        close(fd);
        return 1;
    }

    // 매핑된 메모리에서 JSON 데이터 처리
    printf("파일 내용: %s\n", (char *)mappedMemory);

    // 메모리 매핑 해제
    munmap(mappedMemory, fileSize);
    close(fd);

    return 0;
}

파일 입출력 예외 처리


파일을 읽거나 쓸 때 발생할 수 있는 오류를 적절히 처리하는 것이 중요합니다. 예를 들어, 파일이 존재하지 않거나 읽기/쓰기 권한이 없는 경우, 파일이 손상된 경우 등의 상황을 고려해야 합니다. 오류 처리를 잘하면 애플리케이션의 안정성을 높일 수 있습니다.

예외 처리 예시

FILE *file = fopen("data.json", "r");
if (file == NULL) {
    perror("파일 열기 오류");
    return 1;
}

// 파일 읽기 작업 수행

if (fclose(file) != 0) {
    perror("파일 닫기 오류");
    return 1;
}

쓰기 작업 최적화


JSON 데이터를 파일에 쓸 때는, 여러 번에 걸쳐 작은 데이터를 쓸 경우 성능이 떨어질 수 있습니다. 따라서 한 번에 큰 덩어리로 데이터를 처리하거나, 버퍼를 사용하여 여러 번의 쓰기를 최소화하는 것이 성능을 향상시킬 수 있습니다.

쓰기 최적화 예시

FILE *file = fopen("data.json", "w");
if (file == NULL) {
    perror("파일 열기 오류");
    return 1;
}

char buffer[BUFFER_SIZE];
size_t bytesWritten = fwrite(buffer, 1, sizeof(buffer), file);
if (bytesWritten != sizeof(buffer)) {
    perror("쓰기 오류");
    fclose(file);
    return 1;
}

fclose(file);

성능 최적화를 위한 기타 팁

  • 파일 접근 최적화: JSON 파일을 자주 읽고 쓸 경우, 파일을 한 번에 열고 필요한 만큼 작업을 진행한 후 닫는 것이 좋습니다.
  • 읽기 및 쓰기 모드: 파일을 읽기 전용 모드 "r" 또는 쓰기 전용 모드 "w"로 열고, 필요할 때만 모드를 변경하여 성능을 최적화합니다.
  • 동시 처리: 멀티스레딩을 활용하여 여러 파일을 동시에 처리하거나, 대용량 데이터를 병렬로 처리할 수 있습니다.

JSON 파일의 구조와 규격


C언어에서 JSON 파일을 다룰 때, JSON 파일의 구조와 규격을 이해하는 것은 매우 중요합니다. JSON은 데이터를 구조화된 형태로 표현하는 경량의 데이터 교환 형식으로, 사람이 읽기 쉽고 기계가 파싱하기에 용이합니다. JSON 파일을 제대로 처리하기 위해서는 JSON의 기본 구조와 규격에 대한 이해가 필요합니다.

JSON의 기본 구조


JSON은 기본적으로 두 가지 주요 데이터 구조를 사용합니다: 객체배열. JSON 객체는 키-값 쌍으로 이루어져 있으며, 배열은 순서대로 값들이 나열된 목록입니다.

객체 (Object)


객체는 중괄호 {}로 감싸져 있고, 키와 값은 콜론 :으로 구분됩니다. 키는 문자열이어야 하며, 값은 다양한 데이터 타입이 될 수 있습니다. 각 키-값 쌍은 쉼표 ,로 구분됩니다.

예시: 객체
{
  "name": "John Doe",
  "age": 30,
  "isStudent": false
}

배열 (Array)


배열은 대괄호 []로 감싸져 있으며, 각 값은 쉼표로 구분됩니다. 배열의 값은 여러 타입을 가질 수 있습니다.

예시: 배열
[
  "apple",
  "banana",
  "cherry"
]

JSON 데이터 타입


JSON은 다음과 같은 기본 데이터 타입을 지원합니다.

  • 문자열 (String): 큰따옴표 "로 감싸진 텍스트
  • 숫자 (Number): 정수 또는 부동소수점 숫자
  • 불린 (Boolean): true 또는 false
  • 배열 (Array): 여러 값들의 순서 있는 집합
  • 객체 (Object): 키-값 쌍의 집합
  • null: 비어있는 값
예시: 다양한 데이터 타입
{
  "name": "Alice",
  "age": 25,
  "isStudent": true,
  "courses": ["Math", "Science", "English"],
  "address": {
    "city": "New York",
    "zip": "10001"
  },
  "phoneNumber": null
}

JSON 파일 규격


JSON 파일은 항상 텍스트 형식이며, UTF-8 인코딩을 사용해야 합니다. 또한 JSON 파일에서 각 요소는 다음 규격을 따릅니다.

  • 공백 문자: JSON 파일에서 공백, 탭, 개행 문자 등은 무시됩니다. 이는 가독성을 위해 사용할 수 있습니다.
  • 값의 타입: JSON의 값은 문자열, 숫자, 불린, 배열, 객체 또는 null일 수 있습니다.
  • 데이터 순서: 객체 내에서 키의 순서는 중요하지 않지만, 배열 내의 요소 순서는 중요합니다.

JSON의 데이터 구조 예시

{
  "name": "John Doe",
  "age": 30,
  "isStudent": false,
  "courses": [
    {
      "name": "Math",
      "grade": "A"
    },
    {
      "name": "Science",
      "grade": "B"
    }
  ],
  "address": {
    "street": "123 Main St",
    "city": "Somewhere",
    "zip": "12345"
  }
}

구성 요소 설명

  • name: 문자열 값
  • age: 숫자 값
  • isStudent: 불린 값
  • courses: 배열, 각 배열 항목은 객체
  • address: 객체, 주소 정보를 담고 있음

주요 규격 요약

  • 데이터 구조: JSON은 객체 {}와 배열 []로 데이터를 구조화합니다.
  • 타입: 문자열, 숫자, 불린, 배열, 객체, null 값을 지원합니다.
  • 문법: JSON은 항상 문자열 형식이며, UTF-8 인코딩을 사용하고, 키는 반드시 문자열이어야 합니다.
  • 공백 문자: 공백, 탭, 개행 문자는 무시되며, 가독성을 위해 자유롭게 사용할 수 있습니다.

실제 예제: C언어로 JSON 파일 읽기와 쓰기


C언어에서 JSON 파일을 읽고 쓰는 작업은 실무에서 자주 필요합니다. 이 절에서는 janssoncJSON 라이브러리를 사용하여 실제 JSON 파일을 읽고 쓰는 예제를 제공합니다. 이 예제들은 JSON 파일을 직렬화하고, 파싱하는 과정을 포함하여, 실제 애플리케이션에서 JSON 파일을 처리하는 방법을 보여줍니다.

예제 1: `jansson`을 이용한 JSON 파일 읽기


jansson 라이브러리를 사용하여 JSON 파일을 읽고, 그 데이터를 C언어 구조체로 파싱하는 예제를 보여드립니다.

코드 예시

#include <stdio.h>
#include <jansson.h>

int main() {
    // JSON 파일 열기
    FILE *file = fopen("data.json", "r");
    if (file == NULL) {
        printf("파일을 열 수 없습니다.\n");
        return 1;
    }

    // JSON 객체 파싱
    json_error_t error;
    json_t *root = json_loadf(file, 0, &error);
    if (root == NULL) {
        printf("JSON 파싱 오류: %s\n", error.text);
        fclose(file);
        return 1;
    }

    // JSON 데이터 읽기
    const char *name = json_string_value(json_object_get(root, "name"));
    int age = json_integer_value(json_object_get(root, "age"));
    int isStudent = json_boolean_value(json_object_get(root, "isStudent"));

    // 출력
    printf("Name: %s\n", name);
    printf("Age: %d\n", age);
    printf("Is Student: %s\n", isStudent ? "true" : "false");

    // 메모리 해제
    json_decref(root);
    fclose(file);

    return 0;
}

예제 2: `cJSON`을 이용한 JSON 파일 쓰기


cJSON 라이브러리를 사용하여 JSON 객체를 생성하고, 이를 파일에 쓰는 예제입니다.

코드 예시

#include <stdio.h>
#include <stdlib.h>
#include <cjson/cJSON.h>

int main() {
    // JSON 객체 생성
    cJSON *root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "name", "Alice");
    cJSON_AddNumberToObject(root, "age", 25);
    cJSON_AddBoolToObject(root, "isStudent", 0);

    // JSON 파일 열기
    FILE *file = fopen("data.json", "w");
    if (file == NULL) {
        printf("파일을 열 수 없습니다.\n");
        cJSON_Delete(root);
        return 1;
    }

    // JSON 객체를 파일에 쓰기
    char *json_string = cJSON_Print(root);
    if (json_string == NULL) {
        printf("JSON 직렬화 오류\n");
        cJSON_Delete(root);
        fclose(file);
        return 1;
    }

    fprintf(file, "%s", json_string);  // 파일에 기록
    free(json_string);  // 메모리 해제

    // JSON 객체 메모리 해제
    cJSON_Delete(root);
    fclose(file);

    return 0;
}

예제 3: 대용량 JSON 파일 읽기 성능 최적화


대용량 JSON 파일을 처리할 때는 성능을 최적화하는 것이 중요합니다. 이 예제에서는 mmap()을 사용하여 파일을 메모리로 매핑하고, 이를 통해 빠르게 데이터를 읽는 방법을 보여줍니다.

코드 예시

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>

int main() {
    int fd = open("large_data.json", O_RDONLY);
    if (fd == -1) {
        printf("파일을 열 수 없습니다.\n");
        return 1;
    }

    // 파일 크기 구하기
    off_t file_size = lseek(fd, 0, SEEK_END);

    // 파일을 메모리로 매핑
    void *mapped_mem = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
    if (mapped_mem == MAP_FAILED) {
        printf("메모리 매핑 오류\n");
        close(fd);
        return 1;
    }

    // 매핑된 메모리에서 JSON 데이터 처리
    printf("파일 내용: %s\n", (char *)mapped_mem);

    // 메모리 매핑 해제
    munmap(mapped_mem, file_size);
    close(fd);

    return 0;
}

예제 4: 파일 입출력 예외 처리


파일을 읽고 쓸 때 발생할 수 있는 오류를 처리하는 방법을 보여주는 예제입니다.

코드 예시

#include <stdio.h>

int main() {
    // 파일 열기
    FILE *file = fopen("data.json", "r");
    if (file == NULL) {
        perror("파일 열기 오류");
        return 1;
    }

    // 파일 처리 작업
    // (읽기 또는 쓰기 작업)

    // 파일 닫기
    if (fclose(file) != 0) {
        perror("파일 닫기 오류");
        return 1;
    }

    return 0;
}

주요 포인트

  • C언어에서 JSON 파일을 읽고 쓰려면 외부 라이브러리(jansson, cJSON)를 활용하는 것이 일반적입니다.
  • 대용량 파일을 처리할 때는 메모리 매핑(mmap())을 사용하여 성능을 최적화할 수 있습니다.
  • 파일 입출력 시 발생할 수 있는 오류를 예외 처리하여 안정성을 높이는 것이 중요합니다.

요약


본 기사에서는 C언어에서 JSON 파일을 읽고 쓰는 다양한 방법을 다뤘습니다. janssoncJSON 라이브러리를 이용한 JSON 파일 처리 방법을 설명하고, 성능 최적화와 예외 처리까지 고려한 코드 예제를 제공했습니다. 대용량 파일을 처리할 때는 메모리 매핑을 사용하여 성능을 개선할 수 있으며, 파일 입출력 과정에서 발생할 수 있는 오류를 적절히 처리하는 것이 중요합니다. 이를 통해 C언어에서 효율적으로 JSON 파일을 다룰 수 있는 방법을 이해할 수 있었습니다.