# Python-এ JSON: ফাইল পড়া ও লেখা, CSV, pathlib এবং UTF-8 এনকোডিং

URL: https://skillaria.top/bn/guides/python/json-python

Python-এ JSON নিয়ে কাজের জন্য আছে অন্তর্নির্মিত json মডিউল: json.load খোলা ফাইল থেকে ডেটা পড়ে, json.dump ফাইলে লেখে, আর json.loads ও json.dumps একই কাজ স্ট্রিংয়ে করে। ফাইল খোলা হয় with open(path, encoding="utf-8") দিয়ে, পথ বানানো যায় pathlib.Path দিয়ে, আর টেবিল পড়া হয় csv মডিউলে।

Python-এ JSON নিয়ে কাজ করতে কোনো তৃতীয় পক্ষের library লাগে না: `json` মডিউল স্ট্যান্ডার্ড লাইব্রেরিতে আছে এবং dictionary ও তালিকাকে টেক্সটে, আবার টেক্সটকে তাতে বদলায়। এর সঙ্গে প্রায় সব সময় দরকার হয় আরও তিনটি জিনিস: `with`-সহ `open` ফাংশন, পথের জন্য `pathlib`, এবং টেবিলের জন্য `csv` মডিউল। নিচে সবকিছু ধারাবাহিকভাবে, চলমান কোডসহ, এবং যেসব ফাঁদে সবচেয়ে বেশি পড়তে হয় সেগুলো সহ।

## Python-এর open ফাংশন: মোড ও এনকোডিং

যেকোনো টেক্সট ফাইল খোলা হয় অন্তর্নির্মিত `open(path, mode, encoding=...)` ফাংশন দিয়ে। এটি একটি ফাইল-অবজেক্ট ফেরত দেয়, যার `read`, `readline`, `write` মেথড আছে এবং যা লুপে লাইন ধরে ধরে পার করা যায়।

| মোড | কী করে |
| --- | --- |

| `"r"` | পড়া (ডিফল্ট)। ফাইল না থাকলে `FileNotFoundError` |

| `"w"` | লেখা। ফাইল তৈরি হয় বা **খোলার সঙ্গে সঙ্গেই খালি হয়ে যায়** |

| `"a"` | শেষে যোগ করা, আগের লেখা অক্ষত থাকে |

| `"x"` | নতুন ফাইল তৈরি; আগে থেকে থাকলে `FileExistsError` |

| `"b"` | মোডের সঙ্গে যোগ: বাইট নিয়ে কাজ (`"rb"`, `"wb"`) |

### with কেন দরকার

ফাইল বন্ধ করতেই হয়: নইলে ডেটা ডিস্কে নাও পৌঁছাতে পারে, আর সিস্টেম ফাইল হ্যান্ডেল দখলে রাখে। `with` ব্লক ফাইল স্বয়ংক্রিয়ভাবে বন্ধ করে — ব্লকের ভেতরে ত্রুটি হলেও।

```
with open("notes.txt", "w", encoding="utf-8") as f:
    f.write("প্রথম লাইন\n")
    f.write("দ্বিতীয় লাইন\n")

with open("notes.txt", encoding="utf-8") as f:
    for line in f:
        print(line.rstrip("\n"))
```

লুপে ফাইল পড়লে একবারে একটি লাইন পড়া হয়, পুরো ফাইল মেমোরিতে যায় না — তাই গিগাবাইটের লগও প্রক্রিয়া করা যায়। `f.read()` পুরো বিষয়বস্তু একটি স্ট্রিংয়ে দেয়, আর `f.readlines()` দেয় লাইনের তালিকা।

### স্ট্রিং লিখতে গিয়ে পুরনো লেখা মুছে যাওয়া

নতুনদের সবচেয়ে সাধারণ ভুল: একটি লাইন «যোগ» করতে `"w"` মোডে ফাইল খোলা। `"w"` প্রথম `write`-এর আগেই, খোলার মুহূর্তেই ফাইল খালি করে। শেষে যোগ করতে `"a"` ব্যবহার করুন, আর নিশ্চিত হতে চাইলে যে কোনো ফাইল ওভাররাইট হবে না — `"x"`।

```
with open("log.txt", "a", encoding="utf-8") as f:
    f.write("নতুন এন্ট্রি\n")
```

খেয়াল রাখুন, `write` নিজে থেকে নতুন লাইন যোগ করে না — `"\n"` স্পষ্ট লিখতে হয়। `print(..., file=f)`-ও ব্যবহার করা যায়: সেটি লাইনের শেষে নিজেই পরিবর্তন বসায়।

## UTF-8 এনকোডিং: কেন «বিকৃত অক্ষর» আসে

Python 3.15-এর আগে `encoding` প্যারামিটার ছাড়া `open()` সিস্টেমের এনকোডিং নিত। Linux ও macOS-এ সেটি UTF-8, কিন্তু ইংরেজি বা রুশ লোকেলের Windows-এ cp1252 বা cp1251। সার্ভারে ঠিকঠাক চলা একটি স্ক্রিপ্ট সহকর্মীর ল্যাপটপে «Р•РґР°»-র মতো বিকৃত লেখা দেখাত, অথবা `UnicodeDecodeError` দিয়ে থেমে যেত।

Python 3.15-এ PEP 686 অনুযায়ী UTF-8 মোড ডিফল্টভাবে চালু: `encoding` ছাড়া `open()` সব OS-এ UTF-8 পড়ে ও লেখে। পুরনো আচরণ ফেরাতে পরিবেশ ভেরিয়েবল `PYTHONUTF8=0` বা পতাকা `-X utf8=0`, আর সিস্টেমের এনকোডিং স্পষ্টভাবে চাইলে `encoding="locale"`।

```
import sys
print(sys.flags.utf8_mode)   # Python 3.15-এ 1

open("legacy.txt", encoding="locale")   # সিস্টেমের এনকোডিং
open("old_excel.csv", encoding="cp1251")  # cp1251-এ সংরক্ষিত ফাইল
```

উল্টো দিকও আছে: cp1251-এ সংরক্ষিত পুরনো Excel বা Windows-স্ক্রিপ্টের CSV এখন UTF-8 হিসেবে পড়া হবে এবং `UnicodeDecodeError` দেবে। সমাধান: `encoding="cp1251"` দিয়ে পড়ুন এবং UTF-8-এ আবার সংরক্ষণ করুন। ভালো অভ্যাস একই থাকে — `encoding` স্পষ্ট লিখুন, তাহলে কোড সব সংস্করণে একইভাবে চলে।

## pathlib: পথ হিসেবে অবজেক্ট

পথ স্ট্রিং দিয়ে জোড়া দেওয়া (`"data" + "/" + name`) অসুবিধাজনক এবং বিভিন্ন OS-এ ভেঙে যায়। `pathlib` মডিউলের `Path` ক্লাসে পথ জোড়া হয় `/` অপারেটরে, আর অবজেক্টের স্পষ্ট বৈশিষ্ট্য থাকে।

```
from pathlib import Path

data = Path("data")
csv_path = data / "expenses.csv"

print(csv_path.name)    # expenses.csv
print(csv_path.stem)    # expenses
print(csv_path.suffix)  # .csv
print(csv_path.parent)  # data
print(csv_path.exists())

data.mkdir(parents=True, exist_ok=True)
(data / "hello.txt").write_text("হ্যালো", encoding="utf-8")
print((data / "hello.txt").read_text(encoding="utf-8"))

for p in data.glob("*.csv"):
    print(p)
```

`read_text` ও `write_text` ছোট ফাইলের জন্য `open` + `with`-এর জায়গা নেয়। `Path` অবজেক্ট সাধারণ `open`, `json` ও `csv` — সবাইকে দেওয়া যায়। স্ক্রিপ্টের নিজের ফোল্ডারের সাপেক্ষে পথ পেতে লিখুন: `Path(__file__).parent / "data"`।

Python 3.14-এ `Path`-এ এসেছে `copy()` ও `move()` মেথড, তাই সাধারণ কপির জন্য আর `shutil` লাগে না। একই সংস্করণে স্ট্যান্ডার্ড লাইব্রেরিতে যুক্ত হয়েছে `compression.zstd` মডিউল, Zstandard সংকোচনের জন্য (PEP 784)।

## JSON: load, dump, loads, dumps

JSON হলো একটি টেক্সট ডেটা-বিনিময় ফরম্যাট: API তা পাঠায়, কনফিগ ও রিপোর্ট তাতে থাকে। `json` মডিউল দুটি কাজ করে: সিরিয়ালাইজেশন (Python-অবজেক্ট → JSON-টেক্সট) এবং ডিসিরিয়ালাইজেশন (টেক্সট → অবজেক্ট)। মেথড চারটি, আর এগুলোর মধ্যে বিভ্রান্তি খুবই স্বাভাবিক।

| ফাংশন | কী করে |
| --- | --- |

| `json.dumps(obj)` | অবজেক্ট → JSON স্ট্রিং |

| `json.loads(s)` | JSON স্ট্রিং → অবজেক্ট |

| `json.dump(obj, f)` | অবজেক্ট → খোলা ফাইলে লেখা |

| `json.load(f)` | খোলা ফাইল থেকে JSON পড়া |

মনে রাখার সহজ উপায়: শেষের `s` মানে string — স্ট্রিং নিয়ে কাজ; না থাকলে ফাইল নিয়ে।

### ধরনের মিল

| Python | JSON |
| --- | --- |

| `dict` | অবজেক্ট `{}` |

| `list`, `tuple` | অ্যারে `[]` |

| `str` | স্ট্রিং |

| `int`, `float` | সংখ্যা |

| `True` / `False` | `true` / `false` |

| `None` | `null` |

Tuple পড়ে ফেরার সময় তালিকা হয়ে যায়। আর set, তারিখ ও `Decimal` মডিউল জানে না, তাই পাবেন `TypeError: Object of type ... is not JSON serializable`।

### JSON ফাইলে সংরক্ষণ

```
import json
from pathlib import Path

report = {
    "month": "2026-10",
    "total": 15230.5,
    "categories": {"food": 8200, "transport": 2100},
    "tags": ["home", "work"],
}

path = Path("data/report.json")
path.parent.mkdir(parents=True, exist_ok=True)
with path.open("w", encoding="utf-8") as f:
    json.dump(report, f, ensure_ascii=False, indent=2)
```

`ensure_ascii=False` বাংলা অক্ষর যেমন আছে তেমনই রাখে। এটি না দিলে ফাইলে «খাবার»-এর বদলে আসবে `"খা..."` — এটিও বৈধ JSON, কিন্তু মানুষের পড়ার অযোগ্য। `indent=2` সুন্দরভাবে ইন্ডেন্ট করে।

### JSON ফাইল থেকে পড়া

```
with open("data/report.json", encoding="utf-8") as f:
    data = json.load(f)

print(data["total"])               # 15230.5
print(data["categories"]["food"])  # 8200
```

ফল সাধারণ dictionary বা তালিকা, তার সঙ্গে স্বাভাবিক উপায়ে কাজ করা যায়। ফাইল JSON না হলে বা অর্ধেক লেখা থাকলে আসে `json.JSONDecodeError`, যাতে লাইন ও অবস্থানের নম্বর থাকে — বাইরে থেকে আসা ডেটার ক্ষেত্রে সেটি ধরা উচিত।

### JSON স্ট্রিং পার্স ও সুন্দর আউটপুট

```
import json

raw = '{"name": "Anika", "skills": ["python", "sql"], "active": true}'
user = json.loads(raw)
print(user["skills"][0])   # python

print(json.dumps(user, ensure_ascii=False, indent=2, sort_keys=True))
```

`sort_keys=True` আউটপুটে key-গুলো সাজায় — git-এ ফাইল তুলনা করার জন্য সুবিধাজনক। টার্মিনাল থেকে দ্রুত ফরম্যাট করতে আছে অন্তর্নির্মিত টুল: `python -m json.tool data/report.json`।

HTTP API-র উত্তরও JSON স্ট্রিং। `requests` library সেটি পড়ে `response.json()` মেথডে, যার ভেতরে আছে সেই একই `json.loads`।

### ফাঁদ: JSON-এর key সব সময় স্ট্রিং

```
d = {1: "January", 2: "February"}
back = json.loads(json.dumps(d))
print(back == d)   # False
print(back)        # {'1': 'January', '2': 'February'}
# back[1] -> KeyError, লিখতে হবে back["1"]

fixed = {int(k): v for k, v in back.items()}
```

JSON অবজেক্টের key শুধু স্ট্রিং হতে পারে, তাই সংখ্যা-key সিরিয়ালাইজেশনের পরে স্ট্রিং হয়ে যায়। পড়ার সময় সেগুলো ফেরত রূপান্তর করুন।

### নিজের ধরন: তারিখ ও Decimal

```
import json
from datetime import date

def default(obj):
    if isinstance(obj, date):
        return obj.isoformat()
    raise TypeError(f"সিরিয়ালাইজ করতে পারি না: {type(obj).__name__}")

print(json.dumps({"day": date(2026, 10, 1)}, default=default))
# {"day": "2026-10-01"}
```

`default` প্যারামিটারের ফাংশন প্রতিটি অজানা অবজেক্টের জন্য ডাকা হয়। জটিল ক্ষেত্রে `json.JSONEncoder`-এর উত্তরাধিকারী ক্লাস নিয়ে তার `default` মেথড বদলানো যায়।

### JSON-অ্যারেতে আইটেম যোগ

টেক্সট লগের মতো JSON-এর শেষে যোগ করা যায় না: ফাইলটি পড়তে হয়, বদলাতে হয় এবং পুরোটা লিখতে হয়।

```
path = Path("data/items.json")
items = json.loads(path.read_text(encoding="utf-8")) if path.exists() else []
items.append({"id": len(items) + 1, "title": "নতুন"})
path.write_text(json.dumps(items, ensure_ascii=False, indent=2), encoding="utf-8")
```

রেকর্ড অনেক হলে এবং ক্রমাগত যোগ হলে JSON Lines ফরম্যাট সুবিধাজনক: প্রতি লাইনে একটি JSON-অবজেক্ট, ফাইল খোলা হয় `"a"` মোডে।

## CSV: csv মডিউল

CSV হলো টেক্সট ফাইলে সাজানো টেবিল: লাইন হলো রেকর্ড, মানগুলো কমা দিয়ে আলাদা। `csv` মডিউল উদ্ধৃতি, মানের ভেতরের কমা ও লাইন ভাঙা ঠিকভাবে সামলায়, যা হাতে লেখা `split(",")` করতে পারে না।

```
import csv

with open("data/expenses.csv", newline="", encoding="utf-8") as f:
    reader = csv.DictReader(f)
    total = 0.0
    for row in reader:
        total += float(row["amount"])
        print(row["date"], row["category"], row["amount"])
print("মোট:", total)
```

`csv.DictReader` প্রতিটি লাইনকে ফাইলের হেডার অনুযায়ী dictionary বানায়। সব মান স্ট্রিং: সংখ্যা ও তারিখ নিজে রূপান্তর করুন (`float`, `int`, `date.fromisoformat`)। কিছু অঞ্চলে Excel «;» বিভাজক দিয়ে CSV সংরক্ষণ করে; সেটি পড়তে `delimiter=";"` দিন।

```
rows = [
    {"date": "2026-10-01", "category": "food", "amount": 450},
    {"date": "2026-10-02", "category": "transport", "amount": 60},
]
with open("data/out.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["date", "category", "amount"])
    writer.writeheader()
    writer.writerows(rows)
```

লেখার সময় `newline=""` বাধ্যতামূলক: নইলে Windows-এ লাইনের মাঝে ফাঁকা লাইন আসবে। ফাইল Excel-এ খুলবেন হলে `encoding="utf-8-sig"` ব্যবহার করুন — BOM চিহ্ন Excel-কে UTF-8 চিনতে সাহায্য করে।

## CSV থেকে JSON: পূর্ণ উদাহরণ

```
import csv
import json
from collections import defaultdict
from pathlib import Path

src = Path("data/expenses.csv")
dst = Path("data/report.json")

by_category = defaultdict(float)
with src.open(newline="", encoding="utf-8") as f:
    for row in csv.DictReader(f):
        by_category[row["category"]] += float(row["amount"])

report = {"total": sum(by_category.values()), "categories": dict(by_category)}
dst.write_text(json.dumps(report, ensure_ascii=False, indent=2), encoding="utf-8")
print(dst.read_text(encoding="utf-8"))
```

যেকোনো রিপোর্ট-স্ক্রিপ্টের মূল কাঠামো এটি: CSV-তে ইনপুট, dictionary-তে সমষ্টি, JSON-এ আউটপুট।

## সাধারণ ভুল

- `FileNotFoundError` — পথ আপেক্ষিক, এবং সেটি গণনা হয় বর্তমান চালু ফোল্ডার থেকে, স্ক্রিপ্টের ফোল্ডার থেকে নয়। `Path(__file__).parent` ব্যবহার করুন।
- ফাইল খালি হয়ে গেছে — `"a"`-এর বদলে `"w"` খোলা হয়েছে।
- `UnicodeDecodeError` — ফাইল অন্য এনকোডিংয়ে; স্পষ্টভাবে উল্লেখ করুন (`cp1251`, `utf-8-sig`)।
- `TypeError: Object of type set is not JSON serializable` — তালিকায় রূপান্তর করুন বা `default` পাঠান।
- JSON লোড করার পরে `KeyError` — সংখ্যা-key স্ট্রিং হয়ে গেছে।
- নিজের ফাইলের নাম `json.py` বা `csv.py` — সেটি স্ট্যান্ডার্ড module-কে ঢেকে দেয়, আর `import json` আপনার ফাইলটিই import করে।

## সারসংক্ষেপ

Python-এ JSON-এর জন্য স্ট্যান্ডার্ড লাইব্রেরিই যথেষ্ট: ফাইলের জন্য `json.load`/`json.dump`, স্ট্রিংয়ের জন্য `loads`/`dumps`, আর পাঠযোগ্য আউটপুটের জন্য `ensure_ascii=False` ও `indent`। ফাইল খুলুন `with`-সহ স্পষ্ট এনকোডিংয়ে, পথ বানান `pathlib`-এ, আর টেবিল পড়ুন `csv.DictReader`-এ। কোর্সে এই বিষয়টি বাস্তবে শেখানো হয়েছে: খরচের ট্র্যাকার CSV থেকে খরচ পড়ে এবং রিপোর্ট JSON-এ সংরক্ষণ করে।

## FAQ

**json.load ও json.loads-এর পার্থক্য কী?**

json.load একটি খোলা ফাইল-অবজেক্ট থেকে JSON পড়ে, আর json.loads স্ট্রিং পার্স করে। একইভাবে json.dump ফাইলে লেখে, আর json.dumps স্ট্রিং ফেরত দেয়।

**JSON-এ বাংলা অক্ষর \u-সংকেত ছাড়া কীভাবে রাখব?**

json.dump বা json.dumps-এ ensure_ascii=False দিন, আর ফাইল encoding="utf-8" দিয়ে খুলুন।

**JSON নিয়ে কাজ করতে কি আলাদা library ইনস্টল করতে হবে?**

না, json মডিউল স্ট্যান্ডার্ড লাইব্রেরিতে আছে; শুধু import json লিখলেই হয়।

**JSON-এ তারিখ বা set রাখা যায় কি?**

সরাসরি না: এগুলো রূপান্তর করতে হয় — তারিখ isoformat দিয়ে ISO স্ট্রিংয়ে, set তালিকায়; অথবা default প্যারামিটারে ফাংশন দিতে হয়।

**যে বড় JSON ফাইল মেমোরিতে ধরে না, তা কীভাবে পড়ব?**

স্ট্যান্ডার্ড json.load পুরো ফাইল পড়ে। বড় পরিমাণের জন্য JSON Lines ফরম্যাটে ডেটা রাখুন এবং প্রতি লাইন json.loads দিয়ে আলাদাভাবে পার্স করুন।


---
Source: Skillaria.Top (https://skillaria.top)
