अध्याय 23

फ़ाइलें पढ़ना और लिखना

with open के साथ फ़ाइलें पढ़ना और लिखना, r/w/a/x मोड का अंतर, प्रत्येक पंक्ति के अंत में न्यूलाइन, encoding हमेशा क्यों लिखना चाहिए, और छोटे कार्यों के लिए pathlib।

35 मिनटPython 3.12
  1. 1समस्या
  2. 2समझें
  3. 3उदाहरण
  4. 4अनुमान
  5. 5स्वयं करें
  6. 6चुनौती

वह समस्या जिसे हम हल कर रहे हैं

पिछले तेईस अध्यायों में हमने जो कुछ भी बनाया, वह प्रोग्राम समाप्त होते ही गायब हो गया।

python
basket = []
basket.append("pen")
print(basket)
text
['pen']

इसे फिर से चलाएं और बास्केट फिर से खाली है। सूचियाँ, डिक्शनरी, फ़ंक्शंस — यह सब मेमोरी में रहता है, और मेमोरी केवल तब तक रहती है जब तक प्रोग्राम चलता है।

पिछला अध्याय प्रोग्रामों के बीच कोड साझा करने के बारे में था। यह अध्याय डेटा के बारे में है — कैसे एक रन अपने काम को अगले रन के लिए, या किसी और के लिए छोड़ता है।

python
with open("notes.txt", "w", encoding="utf-8") as fh:
    fh.write("first line
")
    fh.write("second line
")

with open("notes.txt", "r", encoding="utf-8") as fh:
    print(fh.read(), end="")
text
first line
second line

प्रोग्राम समाप्त हो गया है, और notes.txt अभी भी वहीं मौजूद है।

इस मिशन के अंत तक आप सीखेंगे

  • with open(...) के साथ फ़ाइलें पढ़ना और लिखना, और यह समझना कि with क्यों ज़रूरी है
  • यह बताना कि "r", "w", "a" और "x" में क्या अंतर है — विशेष रूप से "w" क्या नष्ट करता है
  • एक समय में एक पंक्ति पढ़ना, और प्रत्येक पंक्ति के अंत में को संभालना
  • यह समझना कि encoding="utf-8" हमेशा क्यों लिखा जाता है
  • छोटे कार्यों के लिए pathlib.Path का उपयोग करना
  • FileNotFoundError और UnicodeDecodeError को समझना

पूर्वापेक्षाएँ: मॉड्यूल्स और इम्पोर्ट.


with क्यों उपयोग करें

फ़ाइल खोलना ऑपरेटिंग सिस्टम से कुछ उधार लेना है, और उधार चुकाना पड़ता है। फ़ाइल को बंद किए बिना, आपने जो लिखा वह कभी डिस्क तक नहीं पहुँच सकता है।

एक with ब्लॉक उस अदायगी को स्वयं करता है — ब्लॉक समाप्त होते ही फ़ाइल बंद हो जाती है, भले ही इसके अंदर कोई त्रुटि आ जाए।

python
with open("notes.txt", "r", encoding="utf-8") as fh:
    text = fh.read()

print(fh.closed)
print(fh.read())
text
True
ValueError: I/O operation on closed file.

इस कोर्स में open() हमेशा with के साथ लिखा जाता है।

पढ़ना (Reading)

पूरी सामग्री एक साथ .read() से आती है:

python
with open("notes.txt", "r", encoding="utf-8") as fh:
    text = fh.read()

print(repr(text))
print(len(text))
text
'first line
second line
'
23

repr का उपयोग जानबूझकर किया गया है, क्योंकि साधारण print लाइन ब्रेक को छुपा देता है। एक फ़ाइल टेक्स्ट का एक लंबा टुकड़ा होती है, जिसके अंदर लाइन एंडिंग के रूप में बैठी होती है।

एक समय में एक पंक्ति

बड़ी फ़ाइल के लिए .read() एक खराब विकल्प है, क्योंकि यह पूरी चीज़ को मेमोरी में उठा लेता है। सीधे फ़ाइल पर लूप चलाने से पायथन एक समय में एक पंक्ति पढ़ता है:

python
with open("orders.txt", "r", encoding="utf-8") as fh:
    for line in fh:
        print(repr(line))
text
'pen,15.0,3
'
'bag,850.0,1
'
'ink,120.0,2
'

प्रत्येक पंक्ति पर समाप्त होती है। इसलिए पहला कदम लगभग हमेशा .strip() होता है:

python
with open("orders.txt", "r", encoding="utf-8") as fh:
    for line in fh:
        name, price, qty = line.strip().split(",")
        print(f"{name:<5} {float(price) * int(qty):>8.2f}")
text
pen      45.00
bag     850.00
ink     240.00

.strip() फिर .split(",") फिर float() और int()। फ़ाइल से निकलने वाली हर चीज़ टेक्स्ट होती है, संख्या कभी नहीं।

लिखना, और एक खतरनाक अक्षर

python
with open("notes.txt", "w", encoding="utf-8") as fh:
    fh.write("new
")

फ़ाइल में पहले old content था। अब केवल:

text
new

"w" फ़ाइल को खाली कर देता है — खोलने के क्षण ही, कुछ भी लिखने से पहले।

जो कुछ है उसे रखने और अंत में जोड़ने के लिए, "a" (append):

python
with open("notes.txt", "a", encoding="utf-8") as fh:
    fh.write("new
")

चार मोड एक पंक्ति में: "r" पढ़ता है, "w" मिटाता है और लिखता है, "a" अंत में जोड़ता है, "x" केवल नई फ़ाइल बनाता है।

`

` आपको स्वयं देना होता है

print आपके लिए पंक्ति तोड़ता है। write ऐसा नहीं करता।

python
rows = ["pen", "bag"]

with open("out.txt", "w", encoding="utf-8") as fh:
    fh.write("
".join(rows) + "
")
text
'pen
bag
'

encoding="utf-8" — हमेशा

encoding के बिना, पायथन ऑपरेटिंग सिस्टम के डिफ़ॉल्ट का उपयोग करता है, जो अलग-अलग मशीनों पर भिन्न होता है।

इसलिए हर बार open() लिखते समय encoding="utf-8" लिखें — पढ़ने और लिखने दोनों के लिए।

pathlib — छोटे कार्यों के लिए एक संक्षिप्त पथ

python
from pathlib import Path

path = Path("orders.txt")
print(path.exists())
print(len(path.read_text(encoding="utf-8").splitlines()))

out = Path("report.txt")
out.write_text("done
", encoding="utf-8")
print(out.read_text(encoding="utf-8"), end="")
text
True
3
done

read_text और write_text आंतरिक रूप से फ़ाइल को खोलते और बंद करते हैं, इसलिए किसी with की आवश्यकता नहीं होती है।


एक संपूर्ण उदाहरण

orders.txt:

text
pen,15.0,3
bag,850.0,1
ink,120.0,2

main.py:

python
"""एक ऑर्डर फ़ाइल पढ़ें, उसका योग करें, और उसके पास एक रिपोर्ट लिखें।"""

from pathlib import Path

TAX_RATE = 0.15


def read_order(path):
    """प्रत्येक पंक्ति name,price,quantity है। खाली पंक्तियाँ छोड़ दी जाती हैं।"""
    lines = []
    for raw in path.read_text(encoding="utf-8").splitlines():
        if not raw.strip():
            continue
        name, price, quantity = raw.split(",")
        lines.append((name, float(price), int(quantity)))
    return lines


def report(lines):
    rows = []
    total = 0.0
    for name, price, quantity in lines:
        amount = round(price * quantity * (1 + TAX_RATE), 2)
        total += amount
        rows.append(f"{name:<6} {quantity:>3} {amount:>9.2f}")
    rows.append("-" * 20)
    rows.append(f"{'total':<6} {'':>3} {total:>9.2f}")
    return rows


def main():
    order = read_order(Path("orders.txt"))
    rows = report(order)

    Path("report.txt").write_text("
".join(rows) + "
", encoding="utf-8")

    print(Path("report.txt").read_text(encoding="utf-8"), end="")
    print()
    print("lines read:", len(order))


if __name__ == "__main__":
    main()
text
pen      3     51.75
bag      1    977.50
ink      2    276.00
--------------------
total        1305.25

lines read: 3

जब यह टूटता है

FileNotFoundError: [Errno 2] No such file or directory: 'orders.txt' फ़ाइल वहाँ नहीं है, या आप प्रोग्राम को किसी दूसरे फ़ोल्डर से चला रहे हैं। पथ उस स्थान से निकाला जाता है जहाँ से आपने इसे चलाया, न कि स्क्रिप्ट के फ़ोल्डर से। print(Path("orders.txt").resolve()) से देखें।

UnicodeDecodeError: 'utf-8' codec can't decode byte ... फ़ाइल किसी अन्य एन्कोडिंग में लिखी गई थी, या यह टेक्स्ट फ़ाइल नहीं है। encoding ठीक करें, या बाइनरी होने पर "rb" के साथ खोलें।

मेरी फ़ाइल की हर चीज़ गायब हो गई इसे "w" के साथ खोला गया था। पढ़ने के लिए "r" और अंत में जोड़ने के लिए "a" का उपयोग करें।