تبدیل CSV به JSON زمانی کاربرد دارد که دادهها در یک فایل جدولی، خروجی Excel، گزارش مالی، لیست محصولات یا Export یک سامانه قدیمی ذخیره شدهاند، اما قرار است در API، JavaScript، Python، پایگاه داده سندگرا یا یک برنامه وب استفاده شوند. در این تبدیل، هر ردیف CSV معمولاً به یک object و نام ستونها به کلیدهای آن object تبدیل میشود. با وجود این سادگی ظاهری، موضوعاتی مانند Header، جداکننده، کوتیشن، خط جدید داخل سلول، تشخیص نوع داده، مقدارهای خالی، Encoding فارسی و امنیت داده میتوانند نتیجه را کاملاً تغییر دهند.
پاسخ سریع: برای تبدیل CSV به JSON، ابتدا فایل CSV را با Parser استاندارد بخوانید، ردیف Header را بهعنوان نام کلیدها در نظر بگیرید و هر ردیف بعدی را به یک object تبدیل کنید. مقدارها در CSV متن هستند؛ بنابراین تبدیل عدد، Boolean، null و تاریخ باید با یک Schema یا قواعد صریح انجام شود. هرگز CSV را فقط با
split(",")تجزیه نکنید، زیرا ویرگول، کوتیشن و خط جدید میتوانند بخشی از مقدار یک سلول باشند.
تبدیل CSV به JSON دقیقاً چگونه انجام میشود؟
CSV یک ساختار دوبعدی از ردیف و ستون است، در حالی که JSON میتواند object، array و دادههای تودرتو را نمایش دهد. رایجترین خروجی تبدیل CSV، آرایهای از objectها است. Header ستونها کلیدهای object را تعیین میکند و هر ردیف داده یک عضو آرایه میشود.
برای مثال این CSV را در نظر بگیرید:
id,name,active
101,سارا,true
102,امیر,false
103,مینا,true
خروجی طبیعی آن چنین است:
[
{
"id": "101",
"name": "سارا",
"active": "true"
},
{
"id": "102",
"name": "امیر",
"active": "false"
},
{
"id": "103",
"name": "مینا",
"active": "true"
}
]
توجه کنید که یک Parser محافظهکار معمولاً تمام مقدارها را String نگه میدارد. تبدیل "101" به Number و "true" به Boolean تصمیمی جداگانه است و بهتر است با Schema یا تنظیمات صریح انجام شود.
چرا استفاده از split برای CSV اشتباه است؟
یک پیادهسازی ساده ممکن است هر خط را با newline و هر ستون را با ویرگول جدا کند. این روش فقط برای دادههای بسیار محدود جواب میدهد. CSV اجازه میدهد مقدار یک سلول شامل delimiter، کوتیشن یا حتی line break باشد، به شرط آنکه quoting درست رعایت شود.
نمونه معتبر:
id,name,address,note
1,سارا,"Tehran, Iran","او گفت ""سلام"""
2,امیر,شیراز,"خط اول
خط دوم"
اگر این متن با split(",") تجزیه شود، آدرس Tehran, Iran به دو ستون میشکند و کوتیشنهای داخلی نیز درست تفسیر نمیشوند. Parser استاندارد باید وضعیت داخل یا خارج کوتیشن را دنبال کند و دو کوتیشن متوالی را یک کوتیشن واقعی در مقدار بداند.
نقش Header در تبدیل CSV به JSON
Header نام کلیدهای JSON را مشخص میکند. یک Header خوب باید یکتا، غیرخالی و پایدار باشد. مشکلات رایج Header عبارتاند از نامهای تکراری، فاصلههای اضافی، ستون بدون نام و نامهایی که در مقصد معنای خاص دارند.
| وضعیت Header | نمونه | راهکار پیشنهادی |
|---|---|---|
| نامهای تکراری | id,name,name | توقف با خطا یا تغییر کنترلشده به name_2 |
| ستون بدون نام | id,,status | اختصاص نامی مانند column_2 یا رد فایل |
| فاصله اضافی | id , name | Trim کردن Header، نه لزوماً مقدارهای داده |
| تفاوت حروف | Name,name | تعریف سیاست case-sensitive یا normalize کردن |
| نام دارای نقطه | address.city | انتخاب بین کلید تخت یا ساخت object تودرتو |
اگر CSV فاقد Header باشد، میتوان نام ستونها را بهصورت column1، column2 و مانند آن تولید کرد، اما خروجی معنای ضعیفتری دارد. راه بهتر این است که فهرست نام ستونها از بیرون به تبدیلکننده داده شود.
تفاوت خروجی آرایهای و object کلیدگذاریشده
خروجی استاندارد معمولاً آرایهای از objectها است:
[
{"id": "A1", "name": "کیبورد"},
{"id": "A2", "name": "ماوس"}
]
گاهی یک ستون یکتا مثل id میتواند کلید object سطح ریشه شود:
{
"A1": {"name": "کیبورد"},
"A2": {"name": "ماوس"}
}
مدل دوم برای lookup سریع مناسب است، اما فقط زمانی امن است که کلید انتخابی در همه ردیفها وجود داشته باشد و تکراری نباشد. در غیر این صورت، یک ردیف میتواند روی ردیف قبلی overwrite شود.
تشخیص نوع داده در CSV
CSV نوع داده را بهصورت ذاتی ذخیره نمیکند. همه سلولها در فایل متناند. هنگام ساخت JSON باید تصمیم بگیرید مقدارها String باقی بمانند یا به نوعهای دیگر تبدیل شوند.
| مقدار CSV | تفسیر احتمالی | ریسک |
|---|---|---|
00123 | String یا Number | اگر Number شود صفرهای ابتدایی حذف میشوند |
true | String یا Boolean | ممکن است متن واقعی کاربر باشد |
NULL | String یا null | بدون قرارداد قابل تشخیص نیست |
2026-08-06 | String یا Date | JSON نوع Date مستقل ندارد |
9007199254740993 | String یا Number بزرگ | در JavaScript ممکن است دقت از بین برود |
| سلول خالی | رشته خالی، null یا مقدار گمشده | معنا باید از Schema تعیین شود |
روش محافظهکارانه
تمام مقدارها را String نگه دارید. این روش از تغییر ناخواسته کد پستی، شماره تلفن، شناسه و عدد بزرگ جلوگیری میکند. بعداً لایه کسبوکار میتواند فیلدهای مشخص را تبدیل کند.
تشخیص خودکار نوع
مقدارهایی که دقیقاً با الگوهای تعریفشده مطابقت دارند به Number، Boolean یا null تبدیل میشوند. این روش راحت است، اما باید گزینه خاموشکردن و گزارش تبدیلها را داشته باشد.
استفاده از Schema
مطمئنترین روش برای Pipeline پایدار، تعریف نوع هر ستون است. برای مثال id از نوع String، price از نوع Number، active از نوع Boolean و note nullable باشد. در این حالت مقدار ناسازگار باید خطا یا هشدار مشخص تولید کند.
سلول خالی، null و مقدار گمشده
در JSON این سه حالت متفاوتاند:
{
"empty": "",
"nullValue": null
}
کلیدی که وجود ندارد نیز حالت سوم است. اما در CSV، یک خانه خالی بهتنهایی مشخص نمیکند کدام معنا موردنظر بوده است. سیاستهای رایج عبارتاند از:
- تبدیل همه سلولهای خالی به رشته خالی.
- تبدیل سلول خالی به null.
- حذف کلید مربوط به سلول خالی از object.
- استفاده از Token صریح مانند
\Nبرای null و نگهداشتن خانه خالی بهعنوان String خالی.
در Export و Import رفتوبرگشتی، باید قرارداد یکسان در هر دو جهت استفاده شود؛ وگرنه اطلاعات معنایی از بین میرود.
Encoding فارسی در تبدیل CSV به JSON
خرابشدن حروف فارسی معمولاً ناشی از تشخیص اشتباه Encoding است، نه مشکل JSON. فایل CSV را با UTF-8 بخوانید. اگر فایل از Excel یا سامانه قدیمی آمده است، ممکن است دارای UTF-8 BOM، Windows-1256 یا Encoding دیگری باشد.
- Encoding را صریح انتخاب کنید و به تشخیص خودکار کورکورانه اعتماد نکنید.
- وجود BOM را در ابتدای Header بررسی کنید؛ وگرنه اولین کلید ممکن است بهصورت
\ufeffidساخته شود. - پس از Parse، نام Header اول را برای کاراکتر BOM پاکسازی کنید.
- فایل JSON خروجی را با UTF-8 ذخیره کنید.
- در Python برای حفظ متن فارسی در خروجی قابلخواندن از
ensure_ascii=Falseاستفاده کنید.
Delimiter و Locale
همه فایلهای CSV با ویرگول جدا نمیشوند. در برخی Localeها semicolon رایج است، چون ویرگول در عددهای اعشاری استفاده میشود. فایل TSV نیز با tab جدا میشود.
تشخیص خودکار delimiter باید بر اساس چند خط نمونه و با درنظرگرفتن quoting انجام شود. شمارش ساده کاراکترها کافی نیست، زیرا delimiter میتواند داخل مقدار کوتیشنشده باشد. در یک سامانه حساس بهتر است کاربر بتواند delimiter را صریح انتخاب کند.
تبدیل CSV به JSON در JavaScript
در پروژه واقعی بهتر است از Parser آزمایششده استفاده شود. نمونه زیر برای درک منطق، quoting و کوتیشنهای دوبرابر را مدیریت میکند و خروجی آرایهای از objectها میسازد:
function parseCsv(text, delimiter = ",") {
const rows = [];
let row = [];
let value = "";
let inQuotes = false;
for (let i = 0; i < text.length; i++) {
const char = text[i];
const next = text[i + 1];
if (inQuotes) {
if (char === '"' && next === '"') {
value += '"';
i++;
} else if (char === '"') {
inQuotes = false;
} else {
value += char;
}
continue;
}
if (char === '"') {
inQuotes = true;
} else if (char === delimiter) {
row.push(value);
value = "";
} else if (char === "\n") {
row.push(value.replace(/\r$/, ""));
rows.push(row);
row = [];
value = "";
} else {
value += char;
}
}
if (inQuotes) {
throw new Error("کوتیشن CSV بسته نشده است.");
}
if (value.length > 0 || row.length > 0) {
row.push(value);
rows.push(row);
}
return rows;
}
function csvToJson(text, delimiter = ",") {
const rows = parseCsv(text.replace(/^\uFEFF/, ""), delimiter);
if (rows.length === 0) return [];
const headers = rows[0].map(header => header.trim());
return rows.slice(1)
.filter(row => row.some(cell => cell !== ""))
.map((row, rowIndex) => {
if (row.length !== headers.length) {
throw new Error(
`تعداد ستونهای ردیف ${rowIndex + 2} با Header برابر نیست.`
);
}
return Object.fromEntries(
headers.map((header, index) => [header, row[index]])
);
});
}
const csv = `id,name,note
1,سارا,"Tehran, Iran"
2,امیر,"او گفت ""سلام"""`;
console.log(JSON.stringify(csvToJson(csv), null, 2));
این نمونه همه مقدارها را String نگه میدارد و برای سادگی فرض میکند line ending استاندارد است. برای فایلهای بسیار بزرگ، malformed CSV، delimiterهای چندگانه و تنظیمات پیشرفته باید از کتابخانهای استفاده شود که Streaming و گزارش خطا را پشتیبانی کند.
تبدیل CSV به JSON در Python
ماژول استاندارد csv در Python quoting و delimiter را مدیریت میکند:
import csv
import json
from pathlib import Path
def csv_to_json(path, delimiter=","):
with open(path, "r", encoding="utf-8-sig", newline="") as file:
reader = csv.DictReader(file, delimiter=delimiter)
if reader.fieldnames is None:
raise ValueError("CSV header is missing")
headers = [name.strip() for name in reader.fieldnames]
if len(headers) != len(set(headers)):
raise ValueError("CSV contains duplicate headers")
records = []
for line_number, row in enumerate(reader, start=2):
normalized = {
key.strip(): value
for key, value in row.items()
}
if None in normalized:
raise ValueError(
f"Too many columns on line {line_number}"
)
records.append(normalized)
return records
records = csv_to_json("products.csv")
Path("products.json").write_text(
json.dumps(records, ensure_ascii=False, indent=2),
encoding="utf-8"
)
Encoding برابر utf-8-sig هم UTF-8 معمولی و هم UTF-8 دارای BOM را میخواند. گزینه newline="" برای رفتار صحیح ماژول csv، بهویژه در مقدارهای چندخطی، مهم است.
تبدیل نوعها با Schema در Python
نمونه زیر تبدیل را فقط برای ستونهای تعریفشده انجام میدهد:
def parse_bool(value):
normalized = value.strip().lower()
if normalized == "true":
return True
if normalized == "false":
return False
raise ValueError(f"Invalid boolean: {value}")
schema = {
"id": str,
"price": float,
"active": parse_bool,
}
def convert_row(row):
result = {}
for key, value in row.items():
converter = schema.get(key, str)
if value == "":
result[key] = None
continue
result[key] = converter(value)
return result
این مدل بهتر از حدس عمومی است، زیرا مشخص میکند کدام ستون مجاز است عدد یا Boolean شود. برای داده مالی، استفاده از نوع decimal بهجای float معمولاً مناسبتر است.
ساخت JSON تودرتو از Headerهای نقطهدار
CSV تخت است، اما میتوان با یک قرارداد Header ساختار تودرتو تولید کرد:
id,name,address.city,address.postalCode
1,مریم,تبریز,51368
خروجی موردنظر:
[
{
"id": "1",
"name": "مریم",
"address": {
"city": "تبریز",
"postalCode": "51368"
}
}
]
این روش به قرارداد نیاز دارد. اگر Header واقعی شامل نقطه باشد، ممکن است با مسیر object اشتباه شود. همچنین برخورد میان address و address.city باید مدیریت شود، زیرا یک کلید نمیتواند هم String و هم object باشد.
تبدیل ستونهای تکرارشونده به Array
گاهی CSV چنین ستونهایی دارد:
id,tag_1,tag_2,tag_3
1,json,csv,api
میتوان آنها را با یک قرارداد به آرایه تبدیل کرد:
[
{
"id": "1",
"tags": ["json", "csv", "api"]
}
]
روش دیگر نگهداری همه اعضا در یک سلول با جداکننده ثانویه است، مانند json|csv|api. این مدل فقط زمانی قابلاعتماد است که escaping جداکننده ثانویه نیز تعریف شده باشد.
خطاهای رایج CSV هنگام تبدیل به JSON
تعداد ستون ناسازگار
اگر Header سه ستون داشته باشد اما یک ردیف چهار مقدار تولید کند، احتمالاً escaping یا delimiter اشتباه است. Parser باید شماره ردیف و مقدار مشکلدار را گزارش کند.
کوتیشن بستهنشده
وجود یک کوتیشن آغازین بدون کوتیشن پایانی میتواند تمام خطوط بعدی را بخشی از یک سلول کند. تبدیلکننده نباید در این حالت خروجی ناقص تولید کند.
Header تکراری
هنگام ساخت object، کلید تکراری باعث overwrite میشود. بهتر است فایل رد شود یا نامها طبق سیاست شفاف یکتا شوند.
ردیفهای خالی
برخی فایلها در پایان یا میان دادهها خط خالی دارند. باید مشخص شود این خطوط نادیده گرفته شوند یا object خالی بسازند. در بیشتر سناریوها نادیدهگرفتن ردیف کاملاً خالی منطقی است.
Delimiter اشتباه
فایلی که با semicolon جدا شده است، اگر با comma خوانده شود، ممکن است هر خط را یک ستون واحد نشان دهد. تشخیص delimiter را کنترل کنید.
BOM در نام ستون اول
اگر BOM پاک نشود، بهجای کلید id کلیدی نامرئی مانند \ufeffid تولید میشود و دسترسی به داده دشوار خواهد شد.
امنیت تبدیل CSV به JSON
- اندازه فایل، تعداد ردیف، تعداد ستون و طول هر سلول را محدود کنید.
- برای فایل آپلودی، پسوند را معیار امنیت ندانید و محتوا را بررسی کنید.
- نام فایل و مسیر ذخیرهسازی را از ورودی خام کاربر نسازید.
- از ثبت کامل داده حساس در Log خطا خودداری کنید.
- هنگام استفاده از کلیدهای CSV برای ساخت object، نامهای خطرناک مانند
__proto__،constructorوprototypeرا در JavaScript کنترل کنید. - JSON تولیدشده را مستقیماً به Query دیتابیس، Template HTML یا فرمان سیستم تزریق نکنید.
- اگر CSV حاوی اطلاعات شخصی است، فایل موقت و خروجی را طبق سیاست نگهداری داده حذف کنید.
نکته مهم این است که CSV Formula Injection عمدتاً هنگام بازشدن CSV در Spreadsheet مطرح میشود. پس از تبدیل به JSON، خطر اصلی تغییر میکند؛ اکنون باید مراقب استفاده ناامن از داده در HTML، دیتابیس، object merging و سایر sinkها باشید.
عملکرد و پردازش فایلهای بزرگ
خواندن کل فایل در حافظه برای CSV بزرگ میتواند پرهزینه باشد. روش بهتر، پردازش Streaming است: Header یکبار خوانده میشود، سپس هر ردیف Parse و object متناظر بهتدریج نوشته میشود.
- برای خروجی بسیار بزرگ، بهجای یک JSON Array کامل از NDJSON استفاده کنید؛ هر خط یک object مستقل است.
- در JSON Array Streaming، مدیریت کاما بین objectها و بستهشدن صحیح براکت پایانی ضروری است.
- Backpressure را رعایت کنید تا سرعت Parser از نوشتن خروجی بیشتر نشود.
- خطا را همراه شماره خط گزارش کنید.
- اگر validation نیازمند بررسی یکتایی کلید است، ممکن است به حافظه یا Storage موقت نیاز باشد.
- برای گزارش پیشرفت، تعداد بایت یا ردیف پردازششده را ثبت کنید.
بهترین روشهای تبدیل CSV به JSON
- از Parser استاندارد استفاده کنید: split دستی برای داده واقعی کافی نیست.
- Encoding و delimiter را صریح کنید: مخصوصاً برای فایلهای فارسی و خروجی Excel.
- Header را اعتبارسنجی کنید: نام خالی و تکراری را قبل از ساخت object مدیریت کنید.
- نوعها را با Schema تبدیل کنید: از حدس بیقاعده پرهیز کنید.
- سیاست سلول خالی را مستند کنید: رشته خالی، null یا حذف کلید.
- ردیف نامعتبر را مخفی نکنید: شماره خط و علت خطا را گزارش کنید.
- برای داده بزرگ Streaming به کار ببرید: از بارگذاری کامل فایل در حافظه جلوگیری کنید.
- کلیدهای خطرناک را فیلتر کنید: مخصوصاً در JavaScript و merge کردن objectها.
- خروجی را با Schema مقصد تست کنید: معتبر بودن JSON به معنی سازگاری معنایی نیست.
چکلیست قبل از استفاده از JSON خروجی
- آیا Encoding فایل ورودی درست تشخیص داده شده است؟
- آیا delimiter صحیح انتخاب شده است؟
- آیا Header وجود دارد و کلیدهای آن یکتا هستند؟
- آیا تمام ردیفها تعداد ستون یکسان دارند؟
- آیا مقدارهای کوتیشنشده و چندخطی درست Parse شدهاند؟
- آیا سلول خالی طبق قرارداد به null، رشته خالی یا حذف کلید تبدیل شده است؟
- آیا کد پستی، شماره تلفن و شناسهها بهاشتباه Number نشدهاند؟
- آیا عددهای بزرگ بدون کاهش دقت حفظ شدهاند؟
- آیا نام کلیدها برای محیط مقصد امناند؟
- آیا JSON خروجی از نظر Syntax معتبر است؟
- آیا ساختار خروجی با API یا Schema مقصد هماهنگ است؟
چه زمانی JSON خروجی باید تخت یا تودرتو باشد؟
اگر مقصد یک جدول، سیستم گزارشگیری یا API ساده است، objectهای تخت معمولاً خواناتر و قابلپیشبینیترند. اگر Headerها یک قرارداد مسیر روشن دارند و مقصد ساختار دامنهای میخواهد، میتوان object تودرتو ساخت. تبدیل خودکار همه نامهای دارای نقطه به مسیر، بدون قرارداد، خطرناک است.
همچنین اگر CSV در واقع چند نوع رکورد یا چند جدول مرتبط را در یک فایل تقلید میکند، شاید تبدیل مستقیم به یک آرایه JSON مناسب نباشد. بهتر است ابتدا مدل داده طراحی و سپس هر گروه به ساختار جداگانه تبدیل شود.
جمعبندی تبدیل CSV به JSON
تبدیل CSV به JSON یعنی نگاشت یک جدول متنی به داده ساختیافته، نه صرفاً جداکردن متن با ویرگول. یک تبدیل مطمئن باید quoting، newline داخل سلول، Header، delimiter، Encoding، نوع داده، سلول خالی و ردیفهای نامعتبر را مدیریت کند. برای بیشتر کاربردها، آرایهای از objectها بهترین خروجی اولیه است و مقدارها بهتر است تا زمانی که Schema مشخص نشده بهصورت String باقی بمانند.
برای انجام سریع این کار میتوانید از ابزار داخلی تبدیل CSV به JSON استفاده کنید. برای بررسی ظاهری ستونها پیش از تبدیل نیز ابزار نمایشگر CSV مفید است و پس از تولید خروجی میتوانید Syntax آن را با اعتبارسنج JSON بررسی کنید.