सारांश
प्रोग्राम जो कुछ गणना करता है, वह उसके समाप्त होते ही मिट जाता है, जब तक कि वह उसे किसी ऐसी जगह लिखकर न छोड़ दे जो उसके बाद भी बनी रहे। यह पाठ उसी जगह, यानी टेक्स्ट फ़ाइल, को प्रस्तुत करता है, और उस विचार को भी जिससे कुछ भी मौलिक रूप से नया सीखे बिना उसका उपयोग किया जा सकता है: फ़ाइल को स्ट्रीम की तरह पढ़ा और लिखा जाता है, उन्हीं संक्रियाओं से जो कीबोर्ड और स्क्रीन के लिए हैं। इसमें std::ifstream और std::ofstream का अध्ययन किया जाता है, उपयोग से पहले यह जाँच कि फ़ाइल खुल गई है, और कार्य फ़ोल्डर, जो तय करता है कि फ़ाइल कहाँ खोजी जाएगी; पढ़ने का सही लूप, while (std::getline(in, line)), बनाम eof() वाला लूप, जो एक डेटा अधिक संसाधित करता है, और उस अतिरिक्त डेटा का ठीक-ठीक कारण; std::println से लिखना, ऐपेंड मोड और ब्लॉक से बाहर निकलते समय बंद होना। पाठ पंक्ति प्रारूपों के साथ समाप्त होता है: फ़ील्डों को अल्पविराम से अलग करना, std::from_chars से उनका सत्यापन करना, और विनिर्देश में यह तय करना कि बिगड़े रूप वाली पंक्तियों का क्या किया जाए।
अधिगम उद्देश्य
- किसी फ़ाइल को पढ़ने या लिखने के लिए खोलना और उपयोग से पहले जाँचना कि वह खुल गई है, उस फ़ाइल में जो मौजूद नहीं है और उस फ़ाइल में जो किसी दूसरे फ़ोल्डर में खोजी जा रही है, भेद करते हुए।
while (std::getline(in, line))से किसी फ़ाइल को पंक्ति-दर-पंक्ति पढ़ना और स्ट्रीम की अवस्था का अनुसरण करते हुए समझाना किwhile (!in.eof())एक डेटा अधिक क्यों संसाधित करता है।std::println(out, …)से परिणाम किसी फ़ाइल में लिखना, उसकी सामग्री को बदलने और अंत में जोड़ने के बीच चुनते हुए।- अल्पविराम से अलग किए गए मानों की फ़ाइल को रिकॉर्डों के एक वेक्टर में संसाधित करना, हर पंक्ति का सत्यापन करते हुए और अमान्य पंक्तियों को उनकी संख्या के साथ सूचित करते हुए।
फ़ाइल एक स्ट्रीम है
स्थायित्व
प्रोग्राम के वेरिएबल मेमोरी में रहते हैं, और प्रोग्राम की मेमोरी उसके समाप्त होने पर मुक्त हो जाती है: उसके बाद का रन कुछ भी याद रखे बिना शुरू होता है। किसी डेटा को उसे बनाने वाले प्रोग्राम के बाद भी बचे रहने के लिए किसी स्थायी माध्यम पर रहना होगा, और सामान्य उपयोग का माध्यम है फ़ाइल: नाम वाला बाइटों का एक अनुक्रम, डिस्क पर सहेजा हुआ, जिसे ऑपरेटिंग सिस्टम एक रन से दूसरे रन तक सुरक्षित रखता है। टेक्स्ट फ़ाइल वह फ़ाइल है जिसके बाइट वर्ण हैं, UTF-8 में, जैसा पाठ टेक्स्ट ASCII नहीं है में देखा गया, और जो वर्ण '\n' से अलग की गई पंक्तियों में व्यवस्थित हैं। यह सबसे साधारण और सबसे टिकाऊ प्रारूप है: कोई भी एडिटर इसे खोल लेता है, कोई भी भाषा इसे पढ़ लेती है, और कोई व्यक्ति एक नज़र में इसकी जाँच कर सकता है।
फिर भी, C++ फ़ाइल को कीबोर्ड से अलग कोई चीज़ नहीं मानती। पाठ इनपुट, आउटपुट और त्रुटियाँ से ही, std::cin एक इनपुट स्ट्रीम है: वर्णों का एक स्रोत जिन्हें क्रम से उपभोग किया जाता है, एक ऐसी अवस्था के साथ जो दर्ज करती है कि अंतिम संक्रिया विफल हुई या नहीं। पढ़ने के लिए खोली गई फ़ाइल एक और इनपुट स्ट्रीम है, std::ifstream प्रकार की (input file stream से); लिखने के लिए खोली गई फ़ाइल एक आउटपुट स्ट्रीम है, std::ofstream प्रकार की। दोनों हेडर <fstream> में घोषित हैं। इससे निकलता है कि पाठ इनपुट को सही ढंग से पढ़ना में std::cin के बारे में जो कुछ सीखा गया, यानी संक्रियक >>, std::getline और त्रुटि-अवस्था, वह फ़ाइल पर बिना बदले लागू होता है।
खोलना और जाँचना
फ़ाइल स्ट्रीम बनाते समय खुलती है, फ़ाइल के नाम को धनुर्कोष्ठकों में रखकर: std::ifstream in{"grades.txt"};। खोलना विफल हो सकता है (फ़ाइल मौजूद नहीं है, उसे पढ़ने की अनुमति नहीं है, नाम ग़लत लिखा है), और विफलता न प्रोग्राम को रोकती है न कोई संदेश देती है: वह स्ट्रीम को त्रुटि-अवस्था में छोड़ देती है। त्रुटि-अवस्था वाली स्ट्रीम, शर्त के रूप में उपयोग होने पर, false होती है; इसलिए जाँच है if (!in), और यह पहली बार पढ़ने से पहले होनी चाहिए। नीचे का प्रोग्राम एक ऐसी फ़ाइल खोलने का प्रयास करता है जो मौजूद नहीं है।
#include <fstream>#include <iostream>#include <print>int main(){ std::ifstream in{"grades.txt"}; if (!in) { std::println(std::cerr, "grades.txt खोली नहीं जा सकी"); return 1; } int first{}; in >> first; std::println("पहला अंक: {}", first);}grades.txt खोली नहीं जा सकीप्रोग्राम कोड 1 के साथ समाप्त हुआ।
तीन बारीकियाँ ध्यान देने योग्य हैं। पहली है std::cerr (<iostream> से), यानी त्रुटि स्ट्रीम: यह मानक आउटपुट की तरह स्क्रीन पर लिखती है, पर यह एक अलग चैनल है, ताकि जब आउटपुट को किसी फ़ाइल की ओर मोड़ा जाए तो त्रुटि-संदेश परिणामों में न मिलें; std::println पहले आर्ग्युमेंट के रूप में वह स्ट्रीम स्वीकार करता है जिसमें उसे लिखना है। दूसरी है return 1;: शून्य से भिन्न समाप्ति-कोड, जैसा पाठ प्रोग्राम की बनावट में देखा गया, प्रोग्राम चलाने वाले को बताता है कि कुछ ग़लत हुआ। तीसरी है यह कि जाँच के बिना क्या होता: त्रुटि-अवस्था वाली स्ट्रीम पर in >> first कुछ नहीं करता, और प्रोग्राम पूरी निश्चिंतता से “पहला अंक: 0” लिख देता। सच जैसा दिखने वाला झूठा परिणाम त्रुटि-संदेश से बुरा है; जिससे इस पाठ का नियम निकलता है: हर फ़ाइल खोलते समय जाँची जाती है।
सापेक्ष पथ और कार्य फ़ोल्डर
नाम "grades.txt" यह नहीं बताता कि फ़ाइल किस फ़ोल्डर में है। ऐसा नाम एक सापेक्ष पथ है, और इसे कार्य फ़ोल्डर से आरंभ करके हल किया जाता है: वह फ़ोल्डर जिससे प्रोग्राम चलाया जाता है, जो ज़रूरी नहीं कि एक्ज़िक्यूटेबल का फ़ोल्डर हो या सोर्स कोड का। नीचे का प्रोग्राम, जो फ़ोल्डर project में एक फ़ाइल data.txt के साथ सहेजा गया है, उस फ़ाइल को खोलता है और उसकी पहली पंक्ति लिखता है; उसे दो बार चलाया गया, पहले project से और फिर उसके ऊपर वाले फ़ोल्डर से।
$ cd project$ g++ -std=c++23 -Wall -Wextra -Wpedantic -Wconversion -Wshadow -g -fsanitize=address,undefined -fno-sanitize-recover=undefined main.cpp -o main$ ./mainपहली पंक्ति: फ़ाइल की ओर से नमस्ते$ cd ..$ ./project/maindata.txt खोली नहीं जा सकीएक्ज़िक्यूटेबल वही है, और फ़ाइल अपनी जगह पर है; बदला केवल कार्य फ़ोल्डर, और उसके साथ वह जगह जहाँ data.txt खोजी जाती है। “फ़ाइल नहीं मिलती” का यही सबसे आम कारण है। जो एडिटर एक बटन से प्रोग्राम चलाता है, वह कार्य फ़ोल्डर अपने आप चुनता है (Visual Studio Code में यह आम तौर पर एडिटर में खुला फ़ोल्डर होता है, हालाँकि यह टास्क की सेटिंग पर निर्भर करता है), इसलिए जब तक यह पता न हो कि एडिटर क्या करता है, टर्मिनल से, डेटा वाले फ़ोल्डर में, चलाना बेहतर है। उलटा प्रलोभन, यानी कोड में "/home/ana/curso/data.txt" या "C:\\Users\\Ana\\data.txt" जैसा कोई निरपेक्ष पथ लिख देना, एक मशीन पर समस्या हल करता है और बाकी सब पर समस्या पैदा करता है: जैसे ही कोई दूसरा व्यक्ति प्रोग्राम चलाता है या फ़ोल्डर हटाया जाता है, प्रोग्राम काम करना बंद कर देता है। अनुशंसित है ज्ञात कार्य फ़ोल्डर के साथ सापेक्ष पथ, या उससे भी अच्छा, फ़ाइल का नाम ऐसे डेटा के रूप में जो उपयोगकर्ता देता है।
सामग्री लोड हो रही है…