गो का उपयोग करके फाइल / से कैसे पढ़ें / लिखें?


284

मैं अपने आप से गो सीखने की कोशिश कर रहा हूं, लेकिन मैं साधारण फाइलों से पढ़ने और लिखने की कोशिश कर रहा हूं।

मैं जहाँ तक प्राप्त कर सकता हूं inFile, _ := os.Open(INFILE, 0, 0), लेकिन वास्तव में फ़ाइल की सामग्री प्राप्त करने का कोई मतलब नहीं है, क्योंकि रीड फ़ंक्शन []byteएक पैरामीटर के रूप में लेता है ।

func (file *File) Read(b []byte) (n int, err Error)

जवाबों:


476

आइए गो में फ़ाइलों को पढ़ने और लिखने के सभी तरीकों की एक 1-संगत सूची बनाएं।

क्योंकि फ़ाइल API हाल ही में बदल गया है और अधिकांश अन्य उत्तर Go 1 के साथ काम नहीं करते हैं। वे भी याद करते हैं bufioजो महत्वपूर्ण IMHO है।

निम्नलिखित उदाहरणों में मैं इसे पढ़ने से और गंतव्य फ़ाइल पर लिखकर एक फ़ाइल की प्रतिलिपि बनाता हूं।

मूल के साथ शुरू करो

package main

import (
    "io"
    "os"
)

func main() {
    // open input file
    fi, err := os.Open("input.txt")
    if err != nil {
        panic(err)
    }
    // close fi on exit and check for its returned error
    defer func() {
        if err := fi.Close(); err != nil {
            panic(err)
        }
    }()

    // open output file
    fo, err := os.Create("output.txt")
    if err != nil {
        panic(err)
    }
    // close fo on exit and check for its returned error
    defer func() {
        if err := fo.Close(); err != nil {
            panic(err)
        }
    }()

    // make a buffer to keep chunks that are read
    buf := make([]byte, 1024)
    for {
        // read a chunk
        n, err := fi.Read(buf)
        if err != nil && err != io.EOF {
            panic(err)
        }
        if n == 0 {
            break
        }

        // write a chunk
        if _, err := fo.Write(buf[:n]); err != nil {
            panic(err)
        }
    }
}

यहाँ मैंने उपयोग किया os.Openऔर os.Createजो सुविधाजनक रैपर हैं os.OpenFile। हमें आमतौर पर OpenFileसीधे कॉल करने की आवश्यकता नहीं होती है ।

ईओएफ का इलाज करने वाला नोटिस। प्रत्येक कॉल Readको भरने की कोशिश करता है buf, और io.EOFयदि ऐसा करने में फ़ाइल के अंत तक पहुँच जाता है तो त्रुटि के रूप में देता है। इस मामले bufमें अभी भी डेटा रखेगा। परिणामी कॉल Readशून्य को रिटर्न के रूप में पढ़ती है और बाइट की संख्या io.EOFत्रुटि के रूप में होती है। किसी अन्य त्रुटि के कारण घबराहट होगी।

का उपयोग करते हुए bufio

package main

import (
    "bufio"
    "io"
    "os"
)

func main() {
    // open input file
    fi, err := os.Open("input.txt")
    if err != nil {
        panic(err)
    }
    // close fi on exit and check for its returned error
    defer func() {
        if err := fi.Close(); err != nil {
            panic(err)
        }
    }()
    // make a read buffer
    r := bufio.NewReader(fi)

    // open output file
    fo, err := os.Create("output.txt")
    if err != nil {
        panic(err)
    }
    // close fo on exit and check for its returned error
    defer func() {
        if err := fo.Close(); err != nil {
            panic(err)
        }
    }()
    // make a write buffer
    w := bufio.NewWriter(fo)

    // make a buffer to keep chunks that are read
    buf := make([]byte, 1024)
    for {
        // read a chunk
        n, err := r.Read(buf)
        if err != nil && err != io.EOF {
            panic(err)
        }
        if n == 0 {
            break
        }

        // write a chunk
        if _, err := w.Write(buf[:n]); err != nil {
            panic(err)
        }
    }

    if err = w.Flush(); err != nil {
        panic(err)
    }
}

bufioसिर्फ यहाँ एक बफर के रूप में काम कर रहा है, क्योंकि हमारे पास डेटा के लिए बहुत कुछ नहीं है। अधिकांश अन्य स्थितियों में (विशेष रूप से पाठ फ़ाइलों के साथ) bufioहमें आसानी से और लचीले ढंग से पढ़ने और लिखने के लिए एक अच्छा एपीआई देकर बहुत उपयोगी है , जबकि यह पर्दे के पीछे बफरिंग को संभालता है।

का उपयोग करते हुए ioutil

package main

import (
    "io/ioutil"
)

func main() {
    // read the whole file at once
    b, err := ioutil.ReadFile("input.txt")
    if err != nil {
        panic(err)
    }

    // write the whole body at once
    err = ioutil.WriteFile("output.txt", b, 0644)
    if err != nil {
        panic(err)
    }
}

बहुत आसान! लेकिन इसका उपयोग केवल तभी करें जब आप सुनिश्चित हों कि आप बड़ी फ़ाइलों के साथ काम नहीं कर रहे हैं।


55
जो कोई भी इस प्रश्न पर ठोकर खाता है, उसके लिए मूल रूप से इन पुस्तकालयों को पेश करने से पहले 2009 में पूछा गया था, इसलिए कृपया इस उत्तर का उपयोग अपने मार्गदर्शक के रूप में करें!
सेठ होनिग

1
Golang.org/pkg/os/#File.Write के अनुसार , जब राइट सभी बाइट्स नहीं लिखा है, यह एक त्रुटि देता है। तो पहले उदाहरण में अतिरिक्त जांच ( panic("error in writing")) आवश्यक नहीं है।
अयेक

15
ध्यान दें कि ये उदाहरण fo.Close () से वापसी की जाँच नहीं कर रहे हैं। लिनक्स मैन पेज क्लोज (2) से: क्लोजर का रिटर्न मान चेक नहीं करना () फिर भी सामान्य लेकिन गंभीर प्रोग्रामिंग एरर है। यह बहुत संभव है कि पिछले लेखन (2) के संचालन में त्रुटियां पहले अंतिम बंद () पर बताई गई हों। फ़ाइल को बंद करते समय रिटर्न वैल्यू की जाँच न करने से डेटा का साइलेंट लॉस हो सकता है। यह विशेष रूप से एनएफएस और डिस्क कोटा के साथ मनाया जा सकता है।
निक क्रेग-वुड

12
तो, "बड़ी" फ़ाइल क्या है? 1KB? 1 एमबी? 1GB? या "बड़ा" मशीन के हार्डवेयर पर निर्भर करता है?
425nesp

3
@ 425nesp यह पूरी फ़ाइल को मेमोरी में पढ़ता है, इसलिए यह रनिंग मशीन में उपलब्ध मेमोरी की मात्रा पर निर्भर करता है।
मुस्तफा

49

यह अच्छा संस्करण है:

package main

import (
  "io/ioutil"; 
  )


func main() {
  contents,_ := ioutil.ReadFile("plikTekstowy.txt")
  println(string(contents))
  ioutil.WriteFile("filename", contents, 0644)
}

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

9
इसके अलावा, 0x777फर्जी है। किसी भी मामले में, यह अधिक होना चाहिए 0644या 0755(ओक्टल, हेक्स नहीं)।
cnst

@cnst ने इसे 0x777 से 0644 में बदल दिया
ट्रेंटन

31

का उपयोग करते हुए io.Copy

package main

import (
    "io"
    "log"
    "os"
)

func main () {
    // open files r and w
    r, err := os.Open("input.txt")
    if err != nil {
        panic(err)
    }
    defer r.Close()

    w, err := os.Create("output.txt")
    if err != nil {
        panic(err)
    }
    defer w.Close()

    // do the actual work
    n, err := io.Copy(w, r)
    if err != nil {
        panic(err)
    }
    log.Printf("Copied %v bytes\n", n)
}

यदि आपको पहिया को फिर से शुरू करने का मन नहीं है, io.Copyऔर io.CopyNआप अच्छी तरह से सेवा कर सकते हैं। यदि आप io.Copy फ़ंक्शन के स्रोत की जांच करते हैं , तो यह गो लाइब्रेरी में पैक किए गए अधिकांश (मूल 'एक, वास्तव में) समाधानों के अलावा कुछ भी नहीं है। वे हालांकि, वह की तुलना में काफी बड़े बफर का उपयोग कर रहे हैं।


5
उल्लेख के लायक एक बात - यह सुनिश्चित करने के लिए कि फ़ाइल की सामग्री डिस्क पर लिखी गई थी, आपको इसके w.Sync()बाद उपयोग करने की आवश्यकता हैio.Copy(w, r)
Shay Tsadok

इसके अलावा, यदि आप पहले से मौजूद फ़ाइल में लिखते हैं, तो io.Copy()केवल वही डेटा लिखेंगा जिसे आप इसे फीड करते हैं, इसलिए यदि मौजूदा फ़ाइल में अधिक सामग्री थी, तो उसे हटाया नहीं जाएगा, जिसके परिणामस्वरूप दूषित फ़ाइल हो सकती है।
Invidian

1
@ इंविडियन यह सब इस बात पर निर्भर करता है कि आप गंतव्य फ़ाइल को कैसे खोलते हैं। यदि आप करते हैं w, err := os.Create("output.txt"), तो आप जो वर्णन करते हैं वह नहीं होता है, क्योंकि "बनाई गई फ़ाइल को क्रिएट करता है या काटता है। यदि फ़ाइल पहले से मौजूद है, तो इसे काट दिया जाता है।" golang.org/pkg/os/#Create
user7610

यह सही उत्तर होना चाहिए क्योंकि यह पहिया को फिर से आविष्कार नहीं करता है जबकि इसे पढ़ने से पहले एक बार में पूरी फ़ाइल को पढ़ने के लिए नहीं है।
एली डेविस

11

नए गो संस्करणों के साथ, फ़ाइल से / से पढ़ना / लिखना आसान है। किसी फ़ाइल से पढ़ने के लिए:

package main

import (
    "fmt"
    "io/ioutil"
)

func main() {
    data, err := ioutil.ReadFile("text.txt")
    if err != nil {
        return
    }
    fmt.Println(string(data))
}

फ़ाइल में लिखने के लिए:

package main

import "os"

func main() {
    file, err := os.Create("text.txt")
    if err != nil {
        return
    }
    defer file.Close()

    file.WriteString("test\nhello")
}

यह फ़ाइल की सामग्री को अधिलेखित कर देगा (यदि यह नहीं था तो एक नई फ़ाइल बनाएं)।


10

[]byteबाइट सरणी के सभी या भाग का एक टुकड़ा (एक विकल्प के समान) है। स्लाइस को सिस्टम के सभी या किसी भाग (स्लाइस) का पता लगाने और एक्सेस करने के लिए सिस्टम के लिए एक छिपे हुए पॉइंटर फ़ील्ड के साथ एक मूल्य संरचना के रूप में सोचो, स्लाइस की लंबाई और क्षमता के लिए प्लस फ़ील्ड, जिसे आप len()और cap()कार्यों का उपयोग करके एक्सेस कर सकते हैं। ।

यहां आपके लिए एक कार्यशील स्टार्टर किट है, जो एक बाइनरी फ़ाइल को पढ़ता है और प्रिंट करता है; आपको inNameअपने सिस्टम पर एक छोटी फ़ाइल को संदर्भित करने के लिए शाब्दिक मूल्य को बदलना होगा ।

package main
import (
    "fmt";
    "os";
)
func main()
{
    inName := "file-rw.bin";
    inPerm :=  0666;
    inFile, inErr := os.Open(inName, os.O_RDONLY, inPerm);
    if inErr == nil {
        inBufLen := 16;
        inBuf := make([]byte, inBufLen);
        n, inErr := inFile.Read(inBuf);
        for inErr == nil {
            fmt.Println(n, inBuf[0:n]);
            n, inErr = inFile.Read(inBuf);
        }
    }
    inErr = inFile.Close();
}

9
गो सम्मेलन पहले त्रुटि के लिए जाँच करने के लिए है, और सामान्य कोड को ifब्लॉक के बाहर रहने दें
hasen

@ न्याय: यदि त्रुटि होने पर फ़ाइल खुली है, तो आप इसे कैसे बंद करते हैं?
पेट्रोस

10
@peterSO: defer का उपयोग करें
जेम्स

लेकिन क्यों एक [256] बाइट को स्वीकार नहीं किया जाता है और स्पष्ट रूप से मूर्खतापूर्ण और क्रियात्मक (लेकिन जाहिर तौर पर गलत नहीं) inBuf: = make ([] बाइट, 256) को स्वीकार किया जाता है?
कार्डिफ स्पेस मैन

7

इसे इस्तेमाल करे:

package main

import (
  "io"; 
  )


func main() {
  contents,_ := io.ReadFile("filename");
  println(string(contents));
  io.WriteFile("filename", contents, 0644);
}

1
यदि आप एक ही बार में पूरी फ़ाइल पढ़ना चाहते हैं तो यह काम करेगा। यदि फ़ाइल वास्तव में बड़ी है या आप केवल उसका हिस्सा पढ़ना चाहते हैं, तो यह वह नहीं हो सकता है जो आप खोज रहे हैं।
इवान शो

3
आपको वास्तव में त्रुटि कोड की जांच करनी चाहिए, और इसे इस तरह से अनदेखा नहीं करना चाहिए !!
hasen

7
इसे अब ioutil पैकेज में स्थानांतरित कर दिया गया है। तो यह ioutil होगा। ReadFile ()
क्रिस्टोफर

मैंने तय किया इसलिए यह 0644 कहता है
जोकिम

1

दस्तावेज़ीकरण को देखकर ऐसा लगता है कि आपको बस [] बाइट के एक बफर की घोषणा करनी चाहिए और इसे पढ़ने के लिए पास करना चाहिए जो बाद में कई पात्रों तक पढ़ेगा और वास्तव में पढ़े जाने वाले पात्रों की संख्या वापस कर देगा (और एक त्रुटि)।

डॉक्स का कहना है

फ़ाइल से लेन (बी) बाइट्स तक पढ़ता है। यह बाइट्स की संख्या और एक त्रुटि, यदि कोई हो, लौटाता है। EOF को EOF के सेट के साथ शून्य गणना द्वारा इंगित किया गया है।

क्या वह काम नहीं करता है?

संपादित करें: इसके अलावा, मुझे लगता है कि आपको ओएस पैकेज का उपयोग करने के बजाय बफ़ियो पैकेज में घोषित रीडर / लेखक इंटरफेस का उपयोग करना चाहिए ।


आपके पास मेरा वोट है क्योंकि आप वास्तव में स्वीकार करते हैं कि दस्तावेज को पढ़ने के दौरान वास्तविक लोग क्या देखते हैं, तोते के बजाय वे जो जाने के आदी हैं, वे याद रखे हुए हैं (याद नहीं पढ़ रहे हैं) जब वे उस फ़ंक्शन के प्रलेखन को पढ़ते हैं जो वे पहले से ही परिचित हैं।
कार्डिफ स्पेस मैन

1

रीड विधि एक बाइट पैरामीटर लेता है क्योंकि वह बफर है जिसे वह पढ़ेगा। यह कुछ हलकों में एक सामान्य मुहावरा है और जब आप इसके बारे में सोचते हैं तो कुछ समझ में आता है।

इस तरह आप यह निर्धारित कर सकते हैं कि पाठक द्वारा कितनी बाइट्स पढ़ी जाएंगी और वापसी का निरीक्षण करके यह देखना होगा कि वास्तव में कितने बाइट्स पढ़े गए थे और किसी भी त्रुटि को उचित तरीके से संभालना था।

जैसा कि दूसरों ने अपने उत्तरों में बताया है कि बुफ़ियो शायद वही है जो आप ज्यादातर फाइलों से पढ़ना चाहते हैं।

मैं एक अन्य संकेत जोड़ूंगा क्योंकि यह वास्तव में उपयोगी है। फ़ाइल से एक पंक्ति पढ़ना, ReadLine पद्धति द्वारा नहीं बल्कि ReadBytes या ReadString विधि द्वारा सर्वोत्तम रूप से पूरा किया जाता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.