पायथन में फ़ाइल प्रबंधन (File Handling)
फ़ाइल खोलना और बंद करना
फ़ाइल file_object = open(file_name, access_mode) से खोली जाती है, जो एक फ़ाइल ऑब्जेक्ट (जिसे फ़ाइल हैंडल भी कहते हैं) लौटाता है, जिसके माध्यम से सारा पढ़ना-लिखना होता है। एक्सेस मोड वैकल्पिक है और डिफ़ॉल्ट "r", केवल-पठन टेक्स्ट, होता है। फ़ाइल ऑब्जेक्ट के तीन गुण हैं: file.closed (बंद होने पर True), file.mode और file.name। फ़ाइल file_object.close() से बंद होती है, जो लिखे जाने की प्रतीक्षा कर रहा सब कुछ फ़ाइल में भेज देता है। with कथन अपना खंड समाप्त होते ही फ़ाइल को स्वतः बंद कर देता है, भीतर अपवाद आ जाए तब भी: with open("myfile.txt", "r") as f:।
| मोड | अनुमति | फ़ाइल मौजूद हो तो | मौजूद न हो तो | पॉइंटर कहाँ से |
|---|---|---|---|---|
| r | केवल पढ़ना | सामग्री सुरक्षित | त्रुटि (FileNotFoundError) | आरंभ |
| r+ | पढ़ना और लिखना | सामग्री सुरक्षित | त्रुटि | आरंभ |
| w | केवल लिखना | सामग्री मिटा दी जाती है | बनाई जाती है | आरंभ |
| w+ | लिखना और पढ़ना | सामग्री मिटा दी जाती है | बनाई जाती है | आरंभ |
| a | केवल जोड़ना (लिखना) | सामग्री सुरक्षित | बनाई जाती है | अंत |
| a+ | जोड़ना और पढ़ना | सामग्री सुरक्षित | बनाई जाती है | अंत |
टेक्स्ट फ़ाइल में लिखना और उससे पढ़ना
write(string)एक स्ट्रिंग लिखता है और लिखे गए वर्णों की संख्या लौटाता है। यह अपनी ओर से कोई न्यूलाइन नहीं जोड़ता, और संख्या को पहले str() से बदलना पड़ता है।writelines(sequence)किसी सूची या टपल की हर स्ट्रिंग लिखता है, यह भी बिना न्यूलाइन जोड़े, और None लौटाता है।f.writelines(["a", "b", "c"])abcलिखता है।read(n)n वर्ण पढ़ता है; बिना तर्क काread()फ़ाइल का शेष भाग एक स्ट्रिंग के रूप में पढ़ता है।readline(n)एक पंक्ति पढ़ता है, उसके \n सहित, या उसके अधिकतम n वर्ण; फ़ाइल के अंत पर यह ख़ाली स्ट्रिंग लौटाता है।readlines()सभी शेष पंक्तियाँ पढ़कर उन्हें स्ट्रिंगों की सूची के रूप में लौटाता है, प्रत्येक अब भी \n पर समाप्त। फ़ाइल ऑब्जेक्ट पर सीधे लूप भी चलाया जा सकता है:for line in f:।
notes.txt नामक फ़ाइल में दो पंक्तियाँ Hello और World हों, प्रत्येक के बाद न्यूलाइन, तो open("notes.txt").readlines() ['Hello\n', 'World\n'] लौटाता है — दो मदें, प्रत्येक अपनी न्यूलाइन सहित। ऐसी सूची छापते या तुलना करते समय \n भूल जाना आम चूक है।
फ़ाइल पॉइंटर: tell() और seek()
पायथन एक फ़ाइल पॉइंटर (ऑफ़सेट) रखता है जो बताता है कि अगला पठन या लेखन कहाँ होगा; हर पठन या लेखन उसे उतना आगे खिसका देता है जितना पढ़ा या लिखा गया। tell() वर्तमान स्थिति पूर्णांक के रूप में लौटाता है — आरंभ से बाइट्स की संख्या। seek(offset, reference_point) उसे खिसकाता है: reference_point 0 का अर्थ आरंभ से (डिफ़ॉल्ट), 1 वर्तमान स्थिति से और 2 अंत से। टेक्स्ट फ़ाइल में शून्य के अलावा ऑफ़सेट केवल आरंभ से प्रयोग होते हैं; सापेक्ष खिसकाव बाइनरी फ़ाइलों के लिए हैं।
हल किया गया उदाहरण। word.txt में केवल एक शब्द PROGRAMMING है। स्थितियाँ 0 से गिनी जाती हैं, अतः seek(3) के बाद पॉइंटर G पर है, read(4) GRAM लौटाता है, और फिर tell() 7 देता है:f = open("word.txt")f.seek(3)print(f.read(4))print(f.tell())
pickle से बाइनरी फ़ाइलें, और CSV फ़ाइलें
कोई सूची, डिक्शनरी या अन्य पायथन ऑब्जेक्ट फ़ाइल में ज्यों-का-त्यों नहीं लिखा जा सकता; पहले उसे बाइट्स की धारा में बदलना पड़ता है। यह रूपांतरण क्रमबद्धीकरण (serialization / pickling) है, और बाइट्स को वापस ऑब्जेक्ट बनाना विक्रमबद्धीकरण (de-serialization / unpickling)। pickle मॉड्यूल दोनों करता है। pickle.dump(data_object, file_object) बाइनरी लेखन मोड ("wb" या "ab") में खुली फ़ाइल में एक ऑब्जेक्ट लिखता है; pickle.load(file_object) "rb" में खुली फ़ाइल से एक ऑब्जेक्ट वापस पढ़ता है। load का हर कॉल अगला ऑब्जेक्ट लौटाता है, और अंतिम ऑब्जेक्ट के बाद load करने पर EOFError उठता है — इसलिए कई रिकॉर्ड वाली फ़ाइलें ऐसे लूप में पढ़ी जाती हैं जो उस अपवाद पर रुकता है।
मानक पठन-लूप हर रिकॉर्ड गिनता है और अंत पर साफ़ रुकता है:import picklecount = 0with open("rec.dat", "rb") as f: while True: try: obj = pickle.load(f) count += 1 except EOFError: break
CSV (कॉमा से अलग किए मान) फ़ाइल एक टेक्स्ट फ़ाइल है जिसकी हर पंक्ति एक रिकॉर्ड है और क्षेत्र कॉमा से अलग हैं — वह रूप जिसमें स्प्रेडशीट निर्यात करती हैं। csv मॉड्यूल इसे पढ़ता-लिखता है। csv.writer(f) एक writer ऑब्जेक्ट देता है जिसका writerow(list) एक रिकॉर्ड और writerows(list_of_lists) कई रिकॉर्ड लिखता है; csv.reader(f) ऐसा ऑब्जेक्ट देता है जो हर पंक्ति को स्ट्रिंगों की सूची के रूप में देता है, संख्याएँ भी स्ट्रिंग। फ़ाइल newline="" के साथ खोली जाती है ताकि पंक्ति-अंत मॉड्यूल नियंत्रित करे और ख़ाली पंक्तियाँ न आएँ।
['101', 'Asha', '88'] के रूप में लौटती है, [101, 'Asha', 88] के रूप में नहीं। अंक जोड़ने हों तो पहले int() से बदलना होगा; स्ट्रिंगों को जोड़ने पर वे आपस में जुड़ जाएँगी।मुख्य बिंदु
- टेक्स्ट फ़ाइलों में \n पर समाप्त पंक्तियों में वर्ण होते हैं; बाइनरी फ़ाइलों में ऐसे बाइट्स होते हैं जो पाठ नहीं हैं, जैसे चित्र या pickle किए ऑब्जेक्ट।
- open() का डिफ़ॉल्ट "r" है; "r" व "r+" को मौजूदा फ़ाइल चाहिए, "w" व "w+" उसे मिटा देते हैं, "a" व "a+" उसे सुरक्षित रख अंत से शुरू करते हैं।
- write() लिखे गए वर्णों की संख्या लौटाता है; न write() न writelines() कोई न्यूलाइन जोड़ता है।
- read(n) n वर्ण पढ़ता है, readline() अपने \n सहित एक पंक्ति, readlines() पंक्तियों की सूची।
- tell() पॉइंटर की स्थिति देता है; seek(offset, 0/1/2) उसे आरंभ, वर्तमान स्थिति या अंत से खिसकाता है।
- pickle.dump() को "wb"/"ab", pickle.load() को "rb" चाहिए, और EOFError रिकॉर्डों का अंत बताता है; csv.reader हर पंक्ति को स्ट्रिंगों की सूची के रूप में देता है।
अभ्यास प्रश्न (8)
उत्तर खोलने से पहले प्रत्येक प्रश्न हल करें। हर व्याख्या सही विकल्प के साथ लुभावना गलत विकल्प भी बताती है, क्योंकि अंक वहीं जाते हैं।
फ़ाइल word.txt में केवल पाठ PROGRAMMING है। यह कोड क्या छापता है?
f = open("word.txt")f.seek(3)print(f.read(4))उत्तर देखें
उत्तर: C — GRAM
स्थितियाँ 0 से शुरू होती हैं, अतः P, R, O स्थान 0 से 2 घेरते हैं और seek(3) पॉइंटर को G पर छोड़ता है; फिर read(4) चार वर्ण G, R, A, M लौटाता है। OGRA स्थितियों को 1 से गिनने से आता है, जो पॉइंटर को एक स्थान पहले रख देता है। GRAMM चार के स्थान पर पाँच वर्ण पढ़ता है, और RAMM एक स्थान बाद से शुरू होता है।किसी प्रोग्राम को एक मौजूदा लॉग फ़ाइल के अंत में नई पंक्तियाँ जोड़नी हैं, उसकी पहले की सामग्री को छेड़े बिना। फ़ाइल किस मोड में खोली जानी चाहिए?
उत्तर देखें
उत्तर: A — "a"
एपेंड मोड फ़ाइल की सामग्री सुरक्षित रखता है और पॉइंटर को अंत पर रखता है, अतः हर लेखन पुरानी सामग्री के बाद होता है। "w" और "w+" भ्रामक हैं: दोनों मौजूदा फ़ाइल को खोलते ही ख़ाली कर देते हैं, अतः लॉग खो जाता। "r" फ़ाइल को केवल पढ़ने के लिए खोलता है और लिखने का कोई भी प्रयास विफल होता।notes.txt में दो पंक्तियाँ हैं: Hello और World, प्रत्येक के बाद न्यूलाइन। print(open("notes.txt").readlines()) क्या दिखाता है?
उत्तर देखें
उत्तर: B — `['Hello\n', 'World\n']`
readlines() हर पंक्ति के लिए एक स्ट्रिंग वाली सूची लौटाता है, और हर स्ट्रिंग अपनी पंक्ति समाप्त करने वाली न्यूलाइन रखती है, अतः सूची 'Hello\n' और 'World\n' दिखाती है। \n छोड़ देना सबसे आम चूक है — उसके लिए हर मद पर strip() लगाना पड़ता। दोनों पंक्तियों वाली एक स्ट्रिंग read() लौटाता है, और वर्णों की सूची किसी स्ट्रिंग पर list() से मिलती।निम्नलिखित कोड द्वारा क्या छापा जाता है?
f = open("out.txt", "w")n = f.write("Hi\n")print(n)f.close()उत्तर देखें
उत्तर: D — 3
write() लिखे गए वर्णों की संख्या लौटाता है, और "Hi\n" तीन वर्ण है — H, i और न्यूलाइन। 2 उत्तर देना न्यूलाइन को अनदेखा करना है, जो टाइप चाहे जैसे हो, एक ही वर्ण है। None वह है जो writelines() लौटाता है, और write() कभी बूलियन नहीं लौटाता।निम्नलिखित में से कौन pickle का प्रयोग कर पायथन सूची L को बाइनरी फ़ाइल में सही ढंग से लिखता है?
उत्तर देखें
उत्तर: C — `pickle.dump(L, open("d.dat", "wb"))`
pickle.dump पहले ऑब्जेक्ट और दूसरे फ़ाइल ऑब्जेक्ट लेता है, और pickle किया डेटा बाइट्स होता है, अतः फ़ाइल बाइनरी लेखन मोड "wb" में खुलनी चाहिए। साधारण "w" से टेक्स्ट फ़ाइल खुलती है, जो dump द्वारा बनाए बाइट्स को अस्वीकार करती है। load पढ़ने वाला फ़ंक्शन है और केवल फ़ाइल लेता है, और dump के दोनों तर्क आपस में बदलने से वस्तु के स्थान पर फ़ाइल चली जाती है।एक लूप pickle.load() से बाइनरी फ़ाइल के रिकॉर्ड तब तक पढ़ता है जब तक कोई शेष न रहे। कौन-सा अपवाद बताता है कि फ़ाइल का अंत आ गया है?
उत्तर देखें
उत्तर: B — EOFError
pickle.load() का हर कॉल अगला सहेजा ऑब्जेक्ट लौटाता है, और अंतिम के बाद किया गया कॉल कोई डेटा नहीं पाता और EOFError उठाता है, इसीलिए पठन-लूप try के भीतर रहता है और उसी अपवाद पर टूटता है। IndexError अनुक्रमों का है, फ़ाइलों का नहीं। FileNotFoundError किसी अनुपस्थित फ़ाइल को खोलते समय आता, उसके अंत पर नहीं, और StopIteration वह है जिसे for लूप भीतर प्रयोग करता है, न कि जिसे load उठाता है।अभिकथन (A): किसी मौजूदा फ़ाइल को "w" मोड में खोलकर तुरंत बंद करने पर फ़ाइल ख़ाली रह जाती है। कारण (R): "w" मोड में फ़ाइल पॉइंटर मौजूदा सामग्री के अंत पर रखा जाता है।
उत्तर देखें
उत्तर: C — A सत्य है, पर R असत्य है
फ़ाइल को "w" मोड में खोलते ही वह तुरंत छोटी (truncate) कर दी जाती है, अतः कुछ न लिखने पर भी पुरानी सामग्री चली जाती है और A सत्य है। R एपेंड मोड का वर्णन है: "w" में पॉइंटर अब ख़ाली हो चुकी फ़ाइल के आरंभ से शुरू होता है, अतः R असत्य है। "दोनों सत्य" चुनना w और a को उलझाना है, जो इस अध्याय का सबसे अधिक परखा जाने वाला भेद है।marks.csv में पंक्ति 101,Asha,88 है। फ़ाइल f के रूप में खोली जाती है और for row in csv.reader(f): print(row) से पढ़ी जाती है। उस पंक्ति के लिए क्या छपता है?
उत्तर देखें
उत्तर: D — `['101', 'Asha', '88']`
csv.reader हर पंक्ति को कॉमा पर तोड़कर क्षेत्रों को सूची के रूप में देता है, और CSV फ़ाइल टेक्स्ट होने के कारण हर क्षेत्र स्ट्रिंग है, संख्याएँ भी। 101 और 88 को बिना उद्धरण वाली सूची मानती है कि मॉड्यूल संख्याएँ बदल देता है, जो वह कभी नहीं करता — अंकगणित से पहले int() चाहिए। कच्ची पंक्ति फ़ाइल को सीधे पढ़ने से मिलती, और reader सूचियाँ देता है, टपल नहीं।