Python으로 CSV를 JSON 변환하기

·Backend Developer·검토자Priya Sharma·게시일

무료 CSV to JSON 변환기을 브라우저에서 직접 사용하세요 — 설치 불필요.

CSV to JSON 변환기 온라인으로 사용하기 →

CSV 파일은 어디에나 있습니다 — 내보낸 보고서, 데이터베이스 덤프, 로그 추출물 등 — 그리고 언젠가는 Python으로 CSV를 JSON으로 변환해야 할 때가 옵니다. 표준 라이브러리는 두 가지 모듈로 이를 처리합니다: csv.DictReader 는 각 행을 Python 딕셔너리로 변환하고, json.dumps() 는 해당 딕셔너리들을 JSON 문자열로 직렬화합니다. 코드 없이 빠르게 변환하려면 CSV to JSON 변환기를 사용하면 브라우저에서 즉시 처리됩니다. 이 가이드는 프로그래밍 방식의 전체 과정을 다룹니다: json.dump() json.dumps(), JSON 파일 쓰기, dataclass 직렬화, CSV 값의 타입 변환, datetime 및 Decimal 처리, 그리고 orjson과 같은 고성능 대안까지. 모든 예제는 Python 3.10+를 대상으로 합니다.

  • csv.DictReader는 딕셔너리 리스트를 생성합니다 — json.dump(rows, f, indent=2)로 전체 리스트를 직렬화하여 JSON 파일을 작성하세요.
  • json.dump()는 파일 객체에 직접 씁니다. json.dumps()는 문자열을 반환합니다. 올바른 것을 선택하면 불필요한 복사를 피할 수 있습니다.
  • CSV 값은 항상 문자열입니다. JSON으로 직렬화하기 전에 숫자 열을 명시적으로 형변환(int(), float())하세요.
  • json.dumps()에 ensure_ascii=False를 전달하면 출력에서 유니코드 문자 — 악센트 이름, 한글 텍스트 등 — 를 보존할 수 있습니다.
  • CSV에서 가져온 datetime, UUID, 또는 Decimal에는 커스텀 폴백 함수와 함께 default= 파라미터를 사용하세요.
Before · json
After · json
order_id,product,quantity,price
ORD-7291,Wireless Keyboard,2,49.99
ORD-7292,USB-C Hub,1,34.50
[
  {
    "order_id": "ORD-7291",
    "product": "Wireless Keyboard",
    "quantity": "2",
    "price": "49.99"
  },
  {
    "order_id": "ORD-7292",
    "product": "USB-C Hub",
    "quantity": "1",
    "price": "34.50"
  }
]
참고:원시 출력에서 quantity와 price가 JSON 문자열("2", "49.99")로 나타남에 주목하세요. CSV에는 타입 시스템이 없습니다 — 모든 값은 문자열입니다. 이 문제를 해결하는 방법은 아래 타입 변환 섹션에서 다룹니다.

json.dumps() — Python 딕셔너리를 JSON 문자열로 직렬화

json 모듈은 모든 Python 설치에 포함되어 있습니다 — pip install 이 필요 없습니다. json.dumps(obj) 는 Python 객체(dict, list, 문자열, 숫자, bool, None)를 받아 유효한 JSON을 담은 str 을 반환합니다. Python 딕셔너리는 JSON 객체와 비슷해 보이지만 근본적으로 다릅니다: 딕셔너리는 메모리 내의 Python 데이터 구조이고, JSON 문자열은 직렬화된 텍스트입니다. json.dumps() 를 호출하면 이 간극을 연결할 수 있습니다.

최소 예제 — 단일 CSV 행을 JSON으로

Python 3.10+
import json

# Python 딕셔너리로 표현된 단일 CSV 행
server_entry = {
    "hostname": "web-prod-03",
    "ip_address": "10.0.12.47",
    "port": 8080,
    "region": "eu-west-1"
}

# 딕셔너리를 JSON 문자열로 변환
json_string = json.dumps(server_entry)
print(json_string)
# {"hostname": "web-prod-03", "ip_address": "10.0.12.47", "port": 8080, "region": "eu-west-1"}
print(type(json_string))
# <class 'str'>

이렇게 하면 압축된 한 줄 JSON이 생성됩니다 — 페이로드와 저장에는 좋지만 읽기에는 불편합니다. indent=2 를 추가하면 사람이 읽기 좋은 출력을 얻을 수 있습니다:

Python 3.10+ — pretty-printed output
import json

server_entry = {
    "hostname": "web-prod-03",
    "ip_address": "10.0.12.47",
    "port": 8080,
    "region": "eu-west-1"
}

pretty_json = json.dumps(server_entry, indent=2)
print(pretty_json)
# {
#   "hostname": "web-prod-03",
#   "ip_address": "10.0.12.47",
#   "port": 8080,
#   "region": "eu-west-1"
# }

거의 매번 사용하는 두 가지 파라미터가 더 있습니다: sort_keys=True 는 딕셔너리 키를 알파벳순으로 정렬하고(버전 간 JSON 파일 비교에 유용), ensure_ascii=False 는 비ASCII 문자를 \uXXXX 시퀀스로 이스케이프하지 않고 그대로 보존합니다.

Python 3.10+ — sort_keys and ensure_ascii
import json

warehouse_record = {
    "sku": "WH-9031",
    "location": "서울 창고 3호",
    "quantity": 240,
    "last_audit": "2026-03-10"
}

output = json.dumps(warehouse_record, indent=2, sort_keys=True, ensure_ascii=False)
print(output)
# {
#   "last_audit": "2026-03-10",
#   "location": "서울 창고 3호",
#   "quantity": 240,
#   "sku": "WH-9031"
# }

separators 파라미터에 대한 간단한 참고사항: 기본값은 (", ", ": ") 로 쉼표와 콜론 뒤에 공백을 추가합니다. 가능한 가장 압축된 출력을 원할 때(JSON을 URL 파라미터에 삽입하거나 API 응답에서 바이트를 절약할 때 유용) separators=(",", ":") 를 전달하세요.

참고:Python 딕셔너리와 JSON 객체는 출력했을 때 거의 동일해 보입니다. 차이점: json.dumps()는 Python True를 JSON true로, None null로 변환하고, 문자열을 큰따옴표로 감쌉니다 (Python은 작은따옴표를 허용하지만 JSON은 허용하지 않습니다). 유효한 JSON을 생성하려면 항상 json.dumps()를 사용하세요 — str()이나 repr()에 의존하지 마세요.

csv.DictReader에서 JSON 파일까지 — 전체 파이프라인

가장 일반적인 실제 작업은 전체 CSV 파일을 읽어 JSON으로 저장하는 것입니다. 10줄 이내의 전체 스크립트를 소개합니다. csv.DictReader dict 객체의 이터레이터를 생성합니다 — 첫 번째 줄을 키로 사용하여 행마다 하나씩. 이를 list() 로 감싸면 모든 행을 Python 리스트에 수집하고, 이는 JSON 배열로 직렬화됩니다.

Python 3.10+ — full CSV to JSON conversion
import csv
import json

# 1단계: CSV 행을 딕셔너리 리스트로 읽기
with open("inventory.csv", "r", encoding="utf-8") as csv_file:
    rows = list(csv.DictReader(csv_file))

# 2단계: 리스트를 JSON 파일로 쓰기
with open("inventory.json", "w", encoding="utf-8") as json_file:
    json.dump(rows, json_file, indent=2, ensure_ascii=False)

print(f"Converted {len(rows)} rows to inventory.json")

두 번의 open() 호출: 하나는 CSV 읽기용, 하나는 JSON 쓰기용. 이것이 전체 패턴입니다. 여기서는 json.dump() (s 없이)를 사용한다는 점에 주목하세요 — 파일 핸들에 직접 씁니다. json.dumps() 를 사용하면 문자열을 반환하고 이를 f.write()로 별도로 써야 합니다. json.dump() 는 전체 문자열을 메모리에 먼저 구성하지 않고 출력을 스트리밍하기 때문에 더 메모리 효율적입니다.

파일 대신 문자열로 JSON이 필요할 때 — API 페이로드에 삽입하거나, stdout에 출력하거나, 데이터베이스 컬럼에 삽입할 때 — json.dumps() 로 전환하세요:

Python 3.10+ — CSV rows as JSON string
import csv
import json

with open("sensors.csv", "r", encoding="utf-8") as f:
    rows = list(csv.DictReader(f))

# 파일에 쓰는 대신 JSON을 문자열로 가져오기
json_payload = json.dumps(rows, indent=2)
print(json_payload)
# [
#   {
#     "sensor_id": "TMP-4401",
#     "location": "7번 빌딩 - 2층",
#     "reading": "22.4",
#     "unit": "celsius"
#   },
#   ...
# ]

단일 행 vs. 전체 데이터셋: 만약 json.dumps(single_dict) 를 호출하면 JSON 객체({...})를 얻습니다. json.dumps(list_of_dicts) 를 호출하면 JSON 배열([{...}, {...}])을 얻습니다. 외부 컨테이너 형태는 전달하는 것에 따라 달라집니다. 대부분의 다운스트림 소비자는 테이블 형식 데이터에 배열을 기대합니다.

비문자열 값 처리 — CSV의 타입 변환

처음 접하는 사람들이 반드시 걸리는 부분이 있습니다: csv.DictReader 는 모든 값을 문자열로 반환합니다. CSV의 숫자 42는 딕셔너리에서 문자열 "42"가 됩니다. 이를 json.dumps()로 직접 직렬화하면 JSON에 "quantity": "42"가 생기고 "quantity": 42가 아닙니다. 타입을 검증하는 API는 이를 거부합니다. 값을 명시적으로 형변환해야 합니다.

Python 3.10+ — type coercion for CSV rows
import csv
import json

def coerce_types(row: dict) -> dict:
    """문자열 값을 적절한 Python 타입으로 변환합니다."""
    return {
        "sensor_id": row["sensor_id"],
        "location": row["location"],
        "temperature": float(row["temperature"]),
        "humidity": float(row["humidity"]),
        "battery_pct": int(row["battery_pct"]),
        "active": row["active"].lower() == "true",
    }

with open("sensor_readings.csv", "r", encoding="utf-8") as f:
    rows = [coerce_types(row) for row in csv.DictReader(f)]

print(json.dumps(rows[0], indent=2))
# {
#   "sensor_id": "TMP-4401",
#   "location": "7번 빌딩 - 2층",
#   "temperature": 22.4,
#   "humidity": 58.3,
#   "battery_pct": 87,
#   "active": true
# }

이제 JSON 출력에서 temperature는 float, battery_pct는 정수, 그리고 active는 불리언입니다. 형변환 함수는 CSV 스키마에 따라 달라집니다 — CSV 데이터에서 타입을 추측하는 범용적인 방법은 없으므로, CSV 형식마다 하나의 함수를 작성합니다.

커스텀 객체와 비표준 타입 직렬화

Python의 json 모듈은 기본적으로 datetime, UUID, Decimal, 또는 커스텀 클래스를 직렬화할 수 없습니다. 이 중 하나에 json.dumps() 를 호출하면 TypeError가 발생합니다. 이를 처리하는 두 가지 방법이 있습니다.

방법 1: default= 파라미터

알 수 없는 타입을 직렬화 가능한 형태로 변환하는 함수를 default= 에 전달하세요. 이 함수는 JSON 인코더가 처리할 수 없는 객체에 대해서만 호출됩니다.

Python 3.10+ — default= for datetime, UUID, Decimal
import json
from datetime import datetime
from decimal import Decimal
from uuid import UUID

def json_serial(obj):
    """비표준 타입을 위한 폴백 직렬화기."""
    if isinstance(obj, datetime):
        return obj.isoformat()
    if isinstance(obj, UUID):
        return str(obj)
    if isinstance(obj, Decimal):
        return float(obj)
    raise TypeError(f"Type {type(obj).__name__} is not JSON serializable")

transaction = {
    "txn_id": UUID("a1b2c3d4-e5f6-7890-abcd-ef1234567890"),
    "amount": Decimal("149.99"),
    "currency": "EUR",
    "processed_at": datetime(2026, 3, 15, 14, 30, 0),
    "gateway": "stripe",
}

print(json.dumps(transaction, indent=2, default=json_serial))
# {
#   "txn_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
#   "amount": 149.99,
#   "currency": "EUR",
#   "processed_at": "2026-03-15T14:30:00",
#   "gateway": "stripe"
# }
경고:default= 함수의 끝에서 인식되지 않는 타입에 대해 TypeError를 항상 발생시키세요. None을 반환하거나 조용히 건너뛰면 데이터 손실에 대한 아무런 알림 없이 출력에 null이 생깁니다.

방법 2: asdict()를 사용한 Dataclass

Python dataclass는 CSV 행에 적절한 타입 정의를 제공합니다. dataclasses.asdict() 를 사용하여 dataclass 인스턴스를 일반 딕셔너리로 변환한 다음 json.dumps()에 전달하세요.

Python 3.10+ — dataclass serialization
import json
from dataclasses import dataclass, asdict
from datetime import datetime

@dataclass
class ShipmentRecord:
    tracking_id: str
    origin: str
    destination: str
    weight_kg: float
    shipped_at: datetime

def json_serial(obj):
    if isinstance(obj, datetime):
        return obj.isoformat()
    raise TypeError(f"Not serializable: {type(obj).__name__}")

shipment = ShipmentRecord(
    tracking_id="SHP-9827",
    origin="인천",
    destination="서울",
    weight_kg=1240.5,
    shipped_at=datetime(2026, 3, 12, 8, 0, 0),
)

print(json.dumps(asdict(shipment), indent=2, default=json_serial))
# {
#   "tracking_id": "SHP-9827",
#   "origin": "인천",
#   "destination": "서울",
#   "weight_kg": 1240.5,
#   "shipped_at": "2026-03-12T08:00:00"
# }
참고:asdict()는 중첩된 dataclass를 재귀적으로 딕셔너리로 변환합니다. dataclass에 다른 dataclass의 리스트가 포함되어 있으면 전체 트리가 변환됩니다 — 추가 코드가 필요 없습니다.

json.dumps() 파라미터 레퍼런스

json.dumps() json.dump() 가 받는 키워드 인수 전체 목록입니다. 두 함수 모두 동일한 파라미터를 받습니다 — json.dump() 는 파일 객체를 위한 첫 번째 인수를 추가로 받습니다.

파라미터
타입
기본값
설명
obj
Any
(필수)
직렬화할 Python 객체 — dict, list, str, int, float, bool, None
indent
int | str | None
None
들여쓰기 수준당 공백 수(또는 문자열). None = 한 줄 압축 출력
sort_keys
bool
False
출력에서 딕셔너리 키를 알파벳순으로 정렬
ensure_ascii
bool
True
비ASCII 문자를 \\uXXXX로 이스케이프. False로 설정하면 UTF-8 직접 출력
default
Callable | None
None
기본값으로 직렬화할 수 없는 객체에 대해 호출되는 함수 — 직렬화 가능한 값을 반환하거나 TypeError를 발생시킴
separators
tuple[str, str] | None
None
(항목구분자, 키구분자)를 재정의. 공백 없는 압축 출력에는 (",", ":")를 사용
skipkeys
bool
False
str, int, float, bool, None이 아닌 딕셔너리 키를 TypeError 없이 건너뜀
allow_nan
bool
True
float("nan"), float("inf"), float("-inf") 허용. False로 설정하면 이 값들에 대해 ValueError 발생
cls
Type[JSONEncoder] | None
None
기본값 대신 사용할 커스텀 JSONEncoder 서브클래스

csv.DictReader — CSV를 Python 딕셔너리로 읽기

csv.DictReader 는 CSV-to-JSON 파이프라인의 나머지 절반입니다. 파일 객체를 감싸고 첫 번째 줄을 필드 이름으로 사용하여 행마다 하나씩 dict 를 생성합니다. csv.reader (일반 리스트를 생성)와 비교했을 때, DictReader는 컬럼에 이름으로 접근할 수 있게 해줍니다 — row[3]과 같은 매직 인덱스가 필요 없습니다.

Python 3.10+ — DictReader with custom delimiter
import csv
import json

# 데이터베이스 내보내기에서 가져온 탭 구분 파일
with open("user_sessions.tsv", "r", encoding="utf-8") as f:
    reader = csv.DictReader(f, delimiter="\t")
    sessions = list(reader)

print(json.dumps(sessions[:2], indent=2))
# [
#   {
#     "session_id": "sess_8f2a91bc",
#     "user_id": "usr_4421",
#     "started_at": "2026-03-15T09:12:00Z",
#     "duration_sec": "342",
#     "pages_viewed": "7"
#   },
#   {
#     "session_id": "sess_3c7d44ef",
#     "user_id": "usr_1187",
#     "started_at": "2026-03-15T09:14:22Z",
#     "duration_sec": "128",
#     "pages_viewed": "3"
#   }
# ]
경고:csv.DictReader는 파일 전체를 지연(lazy) 방식으로 읽습니다 — 한 번에 한 행씩 생성합니다. list(reader)를 호출하면 모든 행이 메모리에 로드됩니다. 수백만 행이 있는 파일의 경우 모두 수집하는 대신 스트리밍 방식으로 행을 처리하세요.

파일 및 API 응답의 CSV 변환

두 가지 실제 시나리오: 디스크에서 CSV 파일을 읽어 변환하는 것과, API 엔드포인트에서 CSV 데이터를 가져오는 것(많은 보고 서비스가 CSV를 반환합니다). 두 경우 모두 적절한 오류 처리가 필요합니다.

CSV 파일 읽기 → 변환 → JSON 쓰기

Python 3.10+ — file conversion with error handling
import csv
import json
import sys

def csv_to_json_file(csv_path: str, json_path: str) -> int:
    """CSV 파일을 JSON으로 변환합니다. 작성된 행 수를 반환합니다."""
    try:
        with open(csv_path, "r", encoding="utf-8") as f:
            rows = list(csv.DictReader(f))
    except FileNotFoundError:
        print(f"Error: {csv_path} not found", file=sys.stderr)
        sys.exit(1)
    except csv.Error as e:
        print(f"CSV parse error in {csv_path}: {e}", file=sys.stderr)
        sys.exit(1)

    with open(json_path, "w", encoding="utf-8") as f:
        json.dump(rows, f, indent=2, ensure_ascii=False)

    return len(rows)

count = csv_to_json_file("fleet_vehicles.csv", "fleet_vehicles.json")
print(f"Wrote {count} records to fleet_vehicles.json")

API에서 CSV 가져오기 → 파싱 → JSON

Python 3.10+ — API CSV response to JSON
import csv
import io
import json
import urllib.request

def fetch_csv_as_json(url: str) -> str:
    """URL에서 CSV를 가져와 JSON 문자열로 반환합니다."""
    try:
        with urllib.request.urlopen(url, timeout=10) as resp:
            raw = resp.read().decode("utf-8")
    except urllib.error.URLError as e:
        raise RuntimeError(f"Failed to fetch {url}: {e}")

    reader = csv.DictReader(io.StringIO(raw))
    rows = list(reader)

    if not rows:
        raise ValueError("CSV response was empty or had no data rows")

    return json.dumps(rows, indent=2, ensure_ascii=False)

# 예시: CSV를 반환하는 내보내기 엔드포인트
try:
    result = fetch_csv_as_json("https://reports.internal/api/v2/daily-metrics.csv")
    print(result)
except (RuntimeError, ValueError) as e:
    print(f"Error: {e}")

두 예제 모두 모든 파일 열기에 명시적으로 encoding="utf-8" 를 사용합니다. 이는 비ASCII 문자가 있는 CSV 파일에서 중요합니다 — 악센트 이름, 특수 문자가 포함된 주소, 한글 텍스트. 명시적 인코딩 없이는 Python이 시스템 기본값으로 폴백하는데, Windows에서는 종종 cp1252이며 멀티바이트 문자를 조용히 깨뜨립니다.

json.loads()로 JSON 출력 검증

CSV를 JSON 문자열로 변환한 후 json.loads() 로 다시 파싱하여 결과를 검증할 수 있습니다. 이 왕복 검증은 인코딩 문제, 깨진 이스케이프 시퀀스, 또는 유효하지 않은 JSON을 생성하는 우발적인 문자열 연결을 잡아냅니다. try/except 블록으로 호출을 감싸세요.

Python 3.10+ — round-trip validation
import json

json_string = json.dumps({"order_id": "ORD-7291", "total": 129.99})

# 다시 파싱하여 유효한 JSON인지 확인
try:
    parsed = json.loads(json_string)
    print(f"Valid JSON with {len(parsed)} keys")
except json.JSONDecodeError as e:
    print(f"Invalid JSON: {e}")
# Valid JSON with 2 keys

커맨드라인 CSV to JSON 변환

스크립트 파일 없이 터미널에서 빠르게 변환합니다. Python의 -c 플래그로 인라인 코드를 실행하고, 결과를 python3 -m json.tool 로 파이프하여 보기 좋게 출력할 수 있습니다.

bash — one-liner CSV to JSON
python3 -c "
import csv, json, sys
rows = list(csv.DictReader(sys.stdin))
json.dump(rows, sys.stdout, indent=2)
" < inventory.csv > inventory.json
bash — pipe CSV file and format with json.tool
python3 -c "import csv,json,sys; print(json.dumps(list(csv.DictReader(sys.stdin))))" < data.csv | python3 -m json.tool
bash — convert and validate with jq
python3 -c "import csv,json,sys; json.dump(list(csv.DictReader(sys.stdin)),sys.stdout)" < report.csv | jq .
참고:python3 -m json.tool은 내장 JSON 포매터입니다. stdin에서 JSON을 읽어 검증하고 4칸 들여쓰기로 출력합니다. CSV-to-JSON 변환이 유효한 출력을 생성했는지 확인하는 데 유용합니다. 2칸 들여쓰기를 원하거나 필터링이 필요하다면 jq를 사용하세요.

고성능 대안 — orjson

내장 json 모듈은 대부분의 CSV 파일에 잘 작동합니다. 하지만 루프에서 수만 행의 데이터셋을 처리하거나, API가 모든 요청에서 CSV 기반 데이터를 직렬화해야 한다면 orjson 이 5–10배 빠릅니다. Rust로 작성되어 str 대신 bytes 를 반환하며, datetime, UUID, numpy 배열을 커스텀 default= 함수 없이 네이티브로 직렬화합니다.

bash — install orjson
pip install orjson
Python 3.10+ — CSV to JSON with orjson
import csv
import orjson

with open("telemetry_events.csv", "r", encoding="utf-8") as f:
    rows = list(csv.DictReader(f))

# orjson.dumps()는 str이 아닌 bytes를 반환합니다
json_bytes = orjson.dumps(rows, option=orjson.OPT_INDENT_2)

with open("telemetry_events.json", "wb") as f:  # 참고: bytes를 위해 "wb"
    f.write(json_bytes)

print(f"Wrote {len(rows)} events ({len(json_bytes)} bytes)")

API가 약간 다릅니다: orjson.dumps() bytes를 반환하고 키워드 인수 대신 option= 플래그를 사용합니다. orjson 출력을 쓸 때는 파일을 바이너리 쓰기 모드 ("wb")로 여세요. 문자열이 필요하면 결과에 .decode("utf-8")를 호출하세요.

구문 강조와 함께 터미널 출력 — rich

터미널에서 CSV-to-JSON 변환을 디버깅할 때 색상 출력이 있으면 더 편리합니다. rich 라이브러리는 JSON을 구문 강조와 함께 렌더링합니다 — 키, 문자열, 숫자, 불리언이 각각 고유한 색상을 갖습니다.

bash — install rich
pip install rich
Python 3.10+ — rich JSON output
import csv
import json
from rich.console import Console
from rich.syntax import Syntax

console = Console()

with open("deployment_log.csv", "r", encoding="utf-8") as f:
    rows = list(csv.DictReader(f))

json_output = json.dumps(rows[:3], indent=2, ensure_ascii=False)
syntax = Syntax(json_output, "json", theme="monokai", line_numbers=True)
console.print(syntax)
경고:rich는 ANSI 이스케이프 코드를 출력에 추가합니다. rich 포맷 출력을 파일이나 API 응답에 쓰지 마세요 — 보이지 않는 제어 문자가 포함됩니다. rich는 터미널 표시에만 사용하세요.

대용량 CSV 파일 처리

list(csv.DictReader(f)) 로 500 MB CSV 파일을 로드하면 전체 데이터셋이 메모리에 할당되고, 그 위에 json.dump() 가 전체 JSON 문자열을 구성합니다. 50–100 MB보다 큰 파일의 경우 스트리밍 방식으로 전환하거나 NDJSON(개행 구분 JSON)을 쓰세요 — 한 줄에 하나의 JSON 객체.

NDJSON — 한 줄에 하나의 JSON 객체

Python 3.10+ — streaming CSV to NDJSON
import csv
import json

def csv_to_ndjson(csv_path: str, ndjson_path: str) -> int:
    """CSV를 NDJSON으로 변환합니다. 한 번에 한 행씩 처리합니다."""
    count = 0
    with open(csv_path, "r", encoding="utf-8") as infile, \
         open(ndjson_path, "w", encoding="utf-8") as outfile:
        for row in csv.DictReader(infile):
            outfile.write(json.dumps(row, ensure_ascii=False) + "\n")
            count += 1
    return count

rows_written = csv_to_ndjson("access_log.csv", "access_log.ndjson")
print(f"Wrote {rows_written} lines to access_log.ndjson")
# 각 줄은 독립적인 JSON 객체입니다:
# {"timestamp":"2026-03-15T09:12:00Z","method":"GET","path":"/api/v2/orders","status":"200"}
# {"timestamp":"2026-03-15T09:12:01Z","method":"POST","path":"/api/v2/payments","status":"201"}

대용량 JSON 입력을 위한 ijson 스트리밍

Python 3.10+ — ijson for reading large JSON
import ijson  # pip install ijson

def count_high_value_orders(json_path: str, threshold: float) -> int:
    """전체 파일을 로드하지 않고 임계값 이상의 주문을 셉니다."""
    count = 0
    with open(json_path, "rb") as f:
        for item in ijson.items(f, "item"):
            if float(item.get("total", 0)) > threshold:
                count += 1
    return count

# 일정한 메모리 사용량으로 2 GB JSON 파일 처리
high_value = count_high_value_orders("all_orders.json", 500.0)
print(f"Found {high_value} orders above $500")
참고:CSV가 50–100 MB를 초과하면 NDJSON 또는 스트리밍으로 전환하세요. ijson은 대용량 JSON 파일을 다시 읽을 때 사용하며, 쓰기 측에서는 위의 NDJSON 패턴이 파일 크기에 관계없이 메모리 사용량을 일정하게 유지합니다.

자주 하는 실수

json.dumps()로 문자열을 만든 후 파일에 별도로 쓰기

문제: json.dumps()는 문자열을 반환합니다. f.write()로 쓰는 것은 작동하지만 메모리에 불필요한 중간 문자열을 생성합니다 — 대용량 데이터셋에서는 낭비입니다.

해결: json.dump(data, f)를 사용하여 파일 객체에 직접 씁니다. 전체 문자열을 먼저 구성하지 않고 출력을 스트리밍합니다.

Before · Python
After · Python
json_string = json.dumps(rows, indent=2)
with open("output.json", "w") as f:
    f.write(json_string)  # 불필요한 중간 문자열
with open("output.json", "w", encoding="utf-8") as f:
    json.dump(rows, f, indent=2, ensure_ascii=False)  # 직접 쓰기
CSV 문자열 값을 숫자로 형변환하지 않기

문제: csv.DictReader는 모든 값을 문자열로 반환합니다. JSON 출력에 "quantity": 5 대신 "quantity": "5"가 포함되어 타입 검증을 하는 API 소비자를 깨뜨립니다.

해결: 직렬화하기 전에 int() 또는 float()로 숫자 열을 명시적으로 형변환하세요.

Before · Python
After · Python
rows = list(csv.DictReader(f))
json.dumps(rows)
# [{"port": "8080", "workers": "4"}]  ← 숫자가 아닌 문자열
rows = list(csv.DictReader(f))
for row in rows:
    row["port"] = int(row["port"])
    row["workers"] = int(row["workers"])
json.dumps(rows)
# [{"port": 8080, "workers": 4}]  ← 올바른 정수
파일 열기에 encoding='utf-8' 생략

문제: Windows에서 기본 인코딩은 cp1252입니다. 비ASCII 문자(악센트 이름, 한글 텍스트)가 조용히 깨지거나 UnicodeDecodeError가 발생합니다.

해결: CSV 읽기와 JSON 쓰기 모두 open()에 항상 encoding='utf-8'을 전달하세요.

Before · Python
After · Python
with open("locations.csv", "r") as f:  # 시스템 기본 인코딩 사용
    rows = list(csv.DictReader(f))
with open("locations.csv", "r", encoding="utf-8") as f:
    rows = list(csv.DictReader(f))
json.dumps() 대신 str() 또는 repr() 사용

문제: str(my_dict)는 Python 구문(작은따옴표, True, None)을 생성하며 유효한 JSON이 아닙니다. API와 JSON 파서가 이를 거부합니다.

해결: 유효한 JSON을 생성하려면 항상 json.dumps()를 사용하세요. True를 true로, None을 null로 변환하고 큰따옴표를 사용합니다.

Before · Python
After · Python
output = str({"active": True, "note": None})
# "{'active': True, 'note': None}"  ← 유효한 JSON이 아님
output = json.dumps({"active": True, "note": None})
# '{"active": true, "note": null}'  ← 유효한 JSON

json.dumps() vs 대안 — 빠른 비교

방법
출력
유효한 JSON
커스텀 타입
속도
설치 필요
json.dumps()
str
default= 파라미터로
기준
아니오 (표준 라이브러리)
json.dump()
파일에 쓰기
default= 파라미터로
기준
아니오 (표준 라이브러리)
csv.DictReader + json
str 또는 파일
default= 파라미터로
기준
아니오 (표준 라이브러리)
pandas to_json()
str 또는 파일
✓ datetime 네이티브
대용량 데이터에서 ~2배 빠름
pip install pandas
orjson.dumps()
bytes
✓ datetime/UUID 네이티브
5–10배 빠름
pip install orjson
dataclasses.asdict() + json
str
default= 파라미터로
기준
아니오 (표준 라이브러리)
polars write_json()
str 또는 파일
✓ datetime 네이티브
대용량 데이터에서 ~3배 빠름
pip install polars

대부분의 CSV-to-JSON 변환에는 표준 라이브러리의 csv + json 조합이 올바른 선택입니다: 의존성이 없고, Python과 함께 제공되며, 어디서나 작동합니다. 프로파일링에서 직렬화가 병목이 된다면 orjson 을 선택하세요 — 규모가 커질수록 속도 차이는 실제로 납니다. pandas 는 JSON으로 변환하기 전에 데이터 정제, 필터링, 또는 집계도 필요할 때 사용하세요. 코드 작성 없이 빠른 변환이 필요하다면 온라인 CSV to JSON 변환기가 즉시 처리합니다.

자주 묻는 질문

Python에서 json.dump()와 json.dumps()의 차이는 무엇인가요?

json.dump(obj, file)은 JSON 출력을 파일류 객체(.write() 메서드가 있는 모든 객체)에 직접 씁니다. json.dumps(obj)는 JSON 형식의 문자열을 반환합니다. 파일에 쓸 때는 json.dump()를, 로깅이나 페이로드 삽입, 소켓 전송 등 JSON을 Python 문자열로 필요로 할 때는 json.dumps()를 사용하세요. 두 함수 모두 동일한 키워드 인수(indent, sort_keys, ensure_ascii, default)를 받습니다.

Python 딕셔너리를 JSON 문자열로 변환하려면 어떻게 하나요?

json.dumps(your_dict)를 호출하면 됩니다. 반환값은 유효한 JSON을 담은 str입니다. 가독성 좋은 출력을 위해 indent=2를 추가하세요. 딕셔너리에 비ASCII 값이 있다면 ensure_ascii=False를 전달하여 악센트 문자나 한글 등을 그대로 보존할 수 있습니다.

Python 3.10+
import json

server_config = {"host": "api.internal", "port": 8443, "debug": False}
json_string = json.dumps(server_config, indent=2)
print(json_string)
# {
#   "host": "api.internal",
#   "port": 8443,
#   "debug": false
# }

Python 딕셔너리 리스트를 JSON 파일로 저장하려면 어떻게 하나요?

UTF-8 인코딩으로 파일을 쓰기 모드로 열고 json.dump(your_list, f, indent=2, ensure_ascii=False)를 호출하세요. 파일 출력에는 항상 json.dumps() 대신 json.dump()를 사용하세요 — 중간 문자열을 메모리에 생성하지 않고 파일 핸들에 직접 씁니다.

Python 3.10+
import json

records = [
    {"order_id": "ORD-4821", "total": 129.99, "currency": "USD"},
    {"order_id": "ORD-4822", "total": 89.50, "currency": "EUR"},
]

with open("orders.json", "w", encoding="utf-8") as f:
    json.dump(records, f, indent=2, ensure_ascii=False)

json.dumps()가 True를 true로, None을 null로 변환하는 이유는 무엇인가요?

Python의 불리언(True, False)과 None은 유효한 JSON 토큰이 아닙니다. JSON 명세는 소문자 true, false, null을 사용합니다. json.dumps()가 이 매핑을 자동으로 처리합니다 — True는 true, False는 false, None은 null이 됩니다. 수동으로 변환할 필요가 없습니다. 반대 방향으로는 json.loads()가 이들을 Python 타입으로 다시 매핑합니다.

CSV 데이터를 JSON으로 변환할 때 datetime 객체를 어떻게 처리하나요?

datetime 객체를 ISO 8601 문자열로 변환하는 default= 함수를 json.dumps()에 전달하세요. default 함수는 json이 기본적으로 직렬화할 수 없는 모든 객체에 대해 호출됩니다. datetime 인스턴스에는 obj.isoformat()을 반환하고 그 외의 경우에는 TypeError를 발생시키세요.

Python 3.10+
import json
from datetime import datetime

def json_default(obj):
    if isinstance(obj, datetime):
        return obj.isoformat()
    raise TypeError(f"Not serializable: {type(obj)}")

event = {"action": "login", "timestamp": datetime(2026, 3, 15, 9, 30, 0)}
print(json.dumps(event, default=json_default))
# {"action": "login", "timestamp": "2026-03-15T09:30:00"}

pandas 없이 CSV를 JSON으로 변환할 수 있나요?

네. Python 표준 라이브러리만으로 충분합니다. csv.DictReader로 각 행을 딕셔너리로 읽고, 행들을 리스트에 모은 뒤, json.dump() 또는 json.dumps()로 직렬화하세요. 서드파티 라이브러리가 필요 없습니다. pandas는 데이터 정제, 타입 추론이 필요하거나 프로젝트의 다른 부분에서 이미 사용 중인 경우에만 추가할 가치가 있습니다.

Python 3.10+
import csv
import json

with open("inventory.csv", "r", encoding="utf-8") as csv_file:
    rows = list(csv.DictReader(csv_file))

with open("inventory.json", "w", encoding="utf-8") as json_file:
    json.dump(rows, json_file, indent=2, ensure_ascii=False)

Python을 작성하지 않고 한 번의 클릭으로 변환하려면 CSV to JSON 변환기를 사용해 보세요 — CSV 데이터를 붙여넣으면 바로 포맷된 JSON 출력을 얻을 수 있습니다.

관련 도구

MS
Maria SantosBackend Developer

Maria is a backend developer specialising in Python and API integration. She has broad experience with data pipelines, serialisation formats, and building reliable server-side services. She is an active member of the Python community and enjoys writing practical, example-driven guides that help developers solve real problems without unnecessary theory.

PS
Priya Sharma기술 검토자

Priya is a data scientist and machine learning engineer who has worked across the full Python data stack — from raw data ingestion and cleaning to model deployment and monitoring. She is passionate about reproducible research, Jupyter-based workflows, and the practical engineering side of ML. She writes about NumPy, Pandas, data serialisation, and the Python patterns that make data pipelines reliable at scale.