Rust और फ़ाइलें: मिथक, डर और वास्तविक दृष्टिकोण
\nक्या आपने कभी सोचा है: "आधुनिक Rust में फ़ाइलों को सही तरीके से कैसे पढ़ा और लिखा जाए?" अगर हाँ, तो आप अकेले नहीं हैं। Stack Overflow पर प्रश्न "Rust 1.x में फ़ाइलों को पढ़ने और लिखने का वास्तविक तरीका क्या है?" ने हज़ारों बार देखा गया और दर्जनों उत्तर मिले। यह समुदाय के लिए एक वास्तविक दर्द है, खासकर उन लोगों के लिए जो Python या JavaScript से आए हैं, जहाँ open() और read() बुनियादी हैं, जबकि Rust में स्वामित्व, उधार और ढेरों ट्रेट्स से निपटना पड़ता है।
इस लेख में, हम Rust 1.x में फ़ाइलों के साथ काम करने के सभी मुख्य तरीकों को विस्तार से समझाएंगे: "बस सब कुछ एक स्ट्रिंग में पढ़ना" से लेकर बड़े लॉग को पंक्ति-दर-पंक्ति कुशलतापूर्वक पढ़ने तक। आप जानेंगे कि कौन सा दृष्टिकोण मुहावरेदार माना जाता है और किसे विशेष मामलों के लिए सुरक्षित रखना बेहतर है। चलिए शुरू करते हैं!
\n\n1. std::fs: मानक शस्त्रागार
\nमॉड्यूल std::fs आपका पहला पड़ाव है। यह फ़ाइलों को पढ़ने, लिखने, कॉपी करने और हटाने के लिए फ़ंक्शन प्रदान करता है। Rust 1.x ने सुविधाजनक रैपरों को स्थिर कर दिया है जो सिस्टम कॉल के साथ अधिकांश निम्न-स्तरीय कार्य को छिपा देते हैं।
पूरी फ़ाइल को स्ट्रिंग में पढ़ना
\nसबसे आसान तरीका std::fs::read_to_string का उपयोग करना है। यह फ़ाइल खोलता है, इसे पूरी तरह से मेमोरी में पढ़ता है, और Result<String> लौटाता है। छोटे कॉन्फ़िग या टेक्स्ट फ़ाइलों के लिए आदर्श।
use std::fs;\n\nfn main() -> std::io::Result<()> {\n let content = fs::read_to_string("hello.txt")?;\n println!("फ़ाइल में है:\\n{}", content);\n Ok(())\n}\nयह तरीका सरल मामलों के लिए वास्तविक मानक है। यह संक्षिप्त, सुरक्षित है और त्रुटियों को संभालने के लिए ? का उपयोग करता है। एकमात्र कमी यह है कि पूरी फ़ाइल मेमोरी में लोड होती है, इसलिए यह गीगाबाइट आकार के लॉग के लिए उपयुक्त नहीं है।
बाइट्स के वेक्टर में पढ़ना
\nयदि आप बाइनरी डेटा (चित्र, आर्काइव) के साथ काम कर रहे हैं, तो std::fs::read का उपयोग करें। यह Vec<u8> लौटाता है।
use std::fs;\n\nfn main() -> std::io::Result<()> {\n let bytes = fs::read("image.png")?;\n println!("{} बाइट पढ़े गए", bytes.len());\n Ok(())\n}\n\nफ़ाइल में लिखना
\nलिखने के लिए std::fs::write का उपयोग करें। यह पथ और डेटा (स्ट्रिंग या बाइट्स की सरणी) लेता है और फ़ाइल बनाता/ओवरराइट करता है।
use std::fs;\n\nfn main() -> std::io::Result<()> {\n fs::write("output.txt", "Hello, Rust!")?;\n Ok(())\n}\nबिल्कुल सरल। लेकिन अगर आपको फ़ाइल के अंत में जोड़ना है, न कि ओवरराइट करना है, तो आपको OpenOptions का उपयोग करना होगा।
2. BufReader और BufWriter: जब आकार मायने रखता है
\nबड़ी फ़ाइलों या बार-बार इनपुट-आउटपुट संचालन के लिए, बफ़र किए गए रैपर मदद करते हैं। वे सिस्टम कॉल की संख्या कम करते हैं, जो प्रदर्शन के लिए महत्वपूर्ण है।
\n\nBufReader के साथ पंक्ति-दर-पंक्ति पढ़ना
\nएक क्लासिक उदाहरण - बड़ी लॉग फ़ाइल को पंक्ति-दर-पंक्ति पढ़ना:
\nuse std::fs::File;\nuse std::io::{BufRead, BufReader};\n\nfn main() -> std::io::Result<()> {\n let file = File::open("large_log.txt")?;\n let reader = BufReader::new(file);\n\n for line in reader.lines() {\n let line = line?;\n println!("{}", line);\n }\n Ok(())\n}\nविधि lines() पंक्तियों का एक इटरेटर लौटाती है, जिनमें से प्रत्येक Result<String> है। लूप के अंदर line? पर ध्यान दें - यह प्रत्येक पंक्ति को पढ़ने में त्रुटियों को संभालता है।
महत्वपूर्ण: lines() न्यूलाइन कैरेक्टर को हटा देता है। यदि आपको उन्हें संरक्षित करने की आवश्यकता है, तो read_until का उपयोग करें या फ़ाइल को Vec<u8> के रूप में पढ़ें।
BufWriter के साथ लिखना
\nबड़ी मात्रा में डेटा लिखते समय बफ़रिंग भी उपयोगी है:
\nuse std::fs::File;\nuse std::io::{BufWriter, Write};\n\nfn main() -> std::io::Result<