जंग 1.x में फ़ाइलों को पढ़ने और लिखने का वास्तविक तरीका क्या है?


136

तुलनात्मक रूप से नया होने के कारण, मैंने फ़ाइलों को पढ़ने और लिखने के कई तरीके देखे हैं। कई लोग बहुत गन्दा स्निपेट रखते हैं, कोई उनके ब्लॉग के लिए आया है, और मैंने (स्टैक ओवरफ्लो पर भी) पाए गए 99% उदाहरण अस्थिर बिल्ड से हैं जो अब काम नहीं करते हैं। अब जब रस्ट स्थिर है, तो फ़ाइलों को पढ़ने या लिखने के लिए एक सरल, पठनीय, गैर-पैनिक स्निपेट क्या है?

यह निकटतम है जो मैंने किसी ऐसी चीज़ के लिए प्राप्त किया है जो पाठ फ़ाइल को पढ़ने के संदर्भ में काम करता है, लेकिन यह अभी भी संकलित नहीं कर रहा है, हालांकि मैं काफी निश्चित हूं कि मैंने वह सब कुछ शामिल किया है जो मुझे होना चाहिए। यह एक स्निपेट के आधार पर है जो मुझे सभी स्थानों के Google+ पर मिला है, और केवल एक चीज जो मैंने बदली है वह यह है कि पुराना BufferedReaderअब बस है BufReader:

use std::fs::File;
use std::io::BufReader;
use std::path::Path;

fn main() {
    let path = Path::new("./textfile");
    let mut file = BufReader::new(File::open(&path));
    for line in file.lines() {
        println!("{}", line);
    }
}

संकलक शिकायत करता है:

error: the trait bound `std::result::Result<std::fs::File, std::io::Error>: std::io::Read` is not satisfied [--explain E0277]
 --> src/main.rs:7:20
  |>
7 |>     let mut file = BufReader::new(File::open(&path));
  |>                    ^^^^^^^^^^^^^^
note: required by `std::io::BufReader::new`

error: no method named `lines` found for type `std::io::BufReader<std::result::Result<std::fs::File, std::io::Error>>` in the current scope
 --> src/main.rs:8:22
  |>
8 |>     for line in file.lines() {
  |>                      ^^^^^

यह योग करने के लिए, मैं जो देख रहा हूँ वह है:

  • संक्षिप्तता
  • पठनीयता
  • सभी संभावित त्रुटियों को कवर करता है
  • घबराता नहीं है

आप फ़ाइल को कैसे पढ़ना चाहते हैं? क्या आप इसे रेखा-दर-पंक्ति चाहते हैं, जैसा आपने दिखाया है? क्या आप यह सब एक तार में चाहते हैं? "फ़ाइल पढ़ने" के लिए एक से अधिक तरीके हैं।
शमपास्टर

या तो ढंग ठीक है। मैंने इसे जानबूझकर खुला छोड़ दिया। यदि इसे एक स्ट्रिंग में सभी एकत्र किया जाता है, तो इसे Vec <String> में विभाजित करना तुच्छ होगा, और इसके विपरीत। समाधान के लिए मेरी खोज में इस बिंदु पर, मैं सिर्फ सुरुचिपूर्ण, अप-टू-डेट जंग फ़ाइल I / O कोड जो काम करता है, देखकर खुश हो जाएगा।
जारेड

3
विशेषता त्रुटि के बारे में ( std::io::Read), ध्यान दें कि जंग में आपको उन लक्षणों को आयात करना होगा जो आप स्पष्ट रूप से उपयोग करने की अपेक्षा करते हैं ; इस प्रकार आप यहाँ एक याद कर रहे हैं use std::io::Read(जो एक use std::io::{Read,BufReader}साथ दो उपयोगों को समेटने के लिए एक हो सकता है )
मैथ्यू एम।

जवाबों:


197

जिन कार्यों को मैं यहां दिखा रहा हूं उनमें से कोई भी अपने दम पर घबराता नहीं है, लेकिन मैं उपयोग expectकर रहा हूं क्योंकि मुझे नहीं पता कि किस तरह की त्रुटि से निपटने में आपके आवेदन में सबसे अच्छा फिट होगा। जाओ पढ़ा प्रोग्रामिंग भाषा जंग की हैंडलिंग त्रुटि पर अध्याय को समझने के लिए उचित रूप से अपने स्वयं के कार्यक्रम में विफलता को संभालने के लिए।

1.26 और उसके बाद जंग

यदि आप अंतर्निहित विवरणों की परवाह नहीं करना चाहते हैं, तो पढ़ने और लिखने के लिए एक-लाइन फ़ंक्शन हैं।

में एक फ़ाइल पढ़ें String

use std::fs;

fn main() {
    let data = fs::read_to_string("/etc/hosts").expect("Unable to read file");
    println!("{}", data);
}

के रूप में एक फ़ाइल पढ़ें Vec<u8>

use std::fs;

fn main() {
    let data = fs::read("/etc/hosts").expect("Unable to read file");
    println!("{}", data.len());
}

एक फ़ाइल लिखें

use std::fs;

fn main() {
    let data = "Some data!";
    fs::write("/tmp/foo", data).expect("Unable to write file");
}

जंग 1.0 और उसके बाद

ये फ़ॉर्म वन-लाइन फ़ंक्शंस की तुलना में थोड़े अधिक वर्बोज़ हैं जो आपके लिए Stringया उनके Vecलिए आवंटित हैं, लेकिन इसमें अधिक शक्तिशाली हैं कि आप आवंटित डेटा का पुन: उपयोग कर सकते हैं या किसी मौजूदा ऑब्जेक्ट को जोड़ सकते हैं।

डेटा पढ़ना

किसी फ़ाइल को पढ़ने के लिए दो मुख्य टुकड़े चाहिए: File और Read

में एक फ़ाइल पढ़ें String

use std::fs::File;
use std::io::Read;

fn main() {
    let mut data = String::new();
    let mut f = File::open("/etc/hosts").expect("Unable to open file");
    f.read_to_string(&mut data).expect("Unable to read string");
    println!("{}", data);
}

के रूप में एक फ़ाइल पढ़ें Vec<u8>

use std::fs::File;
use std::io::Read;

fn main() {
    let mut data = Vec::new();
    let mut f = File::open("/etc/hosts").expect("Unable to open file");
    f.read_to_end(&mut data).expect("Unable to read data");
    println!("{}", data.len());
}

एक फ़ाइल लिखें

एक फ़ाइल लिखना समान है, सिवाय इसके कि हम Writeविशेषता का उपयोग करते हैं और हम हमेशा बाइट्स लिखते हैं। आप String/ a &strको बाइट्स में बदल सकते हैं as_bytes:

use std::fs::File;
use std::io::Write;

fn main() {
    let data = "Some data!";
    let mut f = File::create("/tmp/foo").expect("Unable to create file");
    f.write_all(data.as_bytes()).expect("Unable to write data");
}

बफर आई / ओ

मैंने समुदाय से उपयोग करने BufReaderऔर BufWriterएक फ़ाइल से सीधे पढ़ने के बजाय एक धक्का महसूस किया

एक बफ़र्ड रीडर (या लेखक) I / O अनुरोधों की संख्या को कम करने के लिए एक बफर का उपयोग करता है। उदाहरण के लिए, डिस्क को 256 बार एक्सेस करने के बजाय 256 बाइट्स पढ़ने के लिए डिस्क तक पहुंचना बहुत अधिक कुशल है।

कहा जा रहा है, मुझे विश्वास नहीं है कि एक बफर रीडर / लेखक पूरी फाइल को पढ़ते समय उपयोगी होगा। read_to_endलगता है कि डेटा कुछ बड़े हिस्से में कॉपी किया जा सकता है, इसलिए स्थानांतरण पहले से ही स्वाभाविक रूप से कम I / O अनुरोधों में जमा हो सकता है।

यहाँ पढ़ने के लिए इसका उपयोग करने का एक उदाहरण है:

use std::fs::File;
use std::io::{BufReader, Read};

fn main() {
    let mut data = String::new();
    let f = File::open("/etc/hosts").expect("Unable to open file");
    let mut br = BufReader::new(f);
    br.read_to_string(&mut data).expect("Unable to read string");
    println!("{}", data);
}

और लिखने के लिए:

use std::fs::File;
use std::io::{BufWriter, Write};

fn main() {
    let data = "Some data!";
    let f = File::create("/tmp/foo").expect("Unable to create file");
    let mut f = BufWriter::new(f);
    f.write_all(data.as_bytes()).expect("Unable to write data");
}

BufReaderजब आप लाइन-बाय-लाइन पढ़ना चाहते हैं तो A अधिक उपयोगी है:

use std::fs::File;
use std::io::{BufRead, BufReader};

fn main() {
    let f = File::open("/etc/hosts").expect("Unable to open file");
    let f = BufReader::new(f);

    for line in f.lines() {
        let line = line.expect("Unable to read line");
        println!("Line: {}", line);
    }
}

2
मेरे पास वास्तव में इस बंद को आधार बनाने के लिए बहुत कुछ नहीं है, लेकिन इस पर शोध करते समय मैंने एक फ़ाइल को स्ट्रिंग से सीधे पढ़ने के बजाय BufReader और BufWriter का उपयोग करने के लिए समुदाय से एक धक्का महसूस किया। क्या आप इन वस्तुओं या उनके जवाब में आपके द्वारा दिखाए गए "अधिक शास्त्रीय" संस्करण का उपयोग करने के पेशेवरों और विपक्षों के बारे में ज्यादा जानते हैं?
जारेड

@ मैं आपके प्रश्न का अनुसरण नहीं कर रहा हूं। b"foobar"एक बाइट्स की सरणी के संदर्भ को बनाने के लिए एक शाब्दिक है ( &[u8; N])। जैसे, यह अपरिवर्तनीय है। ऐसा कुछ भी नहीं है जो आपको देता है कि आप सरल तरीके से नहीं कर सकते।
शेमपस्टर

@ शेपस्टर कभी-कभार एनकोडेड स्ट्रिंग के बजाय बाइट-ऐरे रखना फायदेमंद होता है; उदाहरण के लिए, यदि आप एक ऐसी ऐप बनाना चाहते हैं, जो फ़ाइलों को एक स्थान से दूसरे स्थान पर ले जाए, तो आपको कच्ची बाइट्स की आवश्यकता होगी ताकि आप निष्पादन योग्य फ़ाइलों को भ्रष्ट न करें जो कि ऐप प्रोसेस करता है।
दलेक्स

@ TheDaleks हाँ, यही कारण है कि यह उत्तर बताता है कि Vec<u8>पढ़ने और लिखने के लिए कैसे उपयोग किया जाए। वे कच्चे बाइट्स हैं।
शेमास्टर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.