Python-এ JSON: ফাইল পড়া ও লেখা, CSV, pathlib এবং UTF-8 এনকোডিং
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-এ সংরক্ষণ করে।
সাধারণ প্রশ্ন
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 দিয়ে আলাদাভাবে পার্স করুন।
“Python 3.15: от новичка до профи” কোর্সে বিষয়টি অনুশীলনসহ বিস্তারিত শেখানো হয়েছে।
কোর্সে যান