स्ट्रिंग सरणी में पाठ फ़ाइल पढ़ें (और लिखें)


100

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

func ReadLines(sFileName string, iMinLines int) ([]string, bool) {

तथा

func WriteLines(saBuff[]string, sFilename string) (bool) { 

मैं डुप्लिकेट के बजाय किसी मौजूदा का उपयोग करना पसंद करूंगा।


2
एक फाइल से लाइनों को पढ़ने के लिए bufio.Scanner का उपयोग करें, stackoverflow.com/a/16615559/1136018 और golang.org/pkg/bufio
जैक

जवाबों:


124

Go1.1 रिलीज के रूप में, एक bufio.Scanner एपीआई है जो आसानी से एक फ़ाइल से लाइनें पढ़ सकता है। ऊपर से निम्नलिखित उदाहरण पर विचार करें, स्कैनर के साथ फिर से लिखा गया:

package main

import (
    "bufio"
    "fmt"
    "log"
    "os"
)

// readLines reads a whole file into memory
// and returns a slice of its lines.
func readLines(path string) ([]string, error) {
    file, err := os.Open(path)
    if err != nil {
        return nil, err
    }
    defer file.Close()

    var lines []string
    scanner := bufio.NewScanner(file)
    for scanner.Scan() {
        lines = append(lines, scanner.Text())
    }
    return lines, scanner.Err()
}

// writeLines writes the lines to the given file.
func writeLines(lines []string, path string) error {
    file, err := os.Create(path)
    if err != nil {
        return err
    }
    defer file.Close()

    w := bufio.NewWriter(file)
    for _, line := range lines {
        fmt.Fprintln(w, line)
    }
    return w.Flush()
}

func main() {
    lines, err := readLines("foo.in.txt")
    if err != nil {
        log.Fatalf("readLines: %s", err)
    }
    for i, line := range lines {
        fmt.Println(i, line)
    }

    if err := writeLines(lines, "foo.out.txt"); err != nil {
        log.Fatalf("writeLines: %s", err)
    }
}

124

यदि फ़ाइल बहुत बड़ी नहीं है, इस के साथ किया जा सकता है ioutil.ReadFileऔर strings.Splitकार्यों इतना चाहते:

content, err := ioutil.ReadFile(filename)
if err != nil {
    //Do something
}
lines := strings.Split(string(content), "\n")

आप दस्तावेज़ को पढ़ सकते हैं ioutil और स्ट्रिंग्स पैकेज ।


5
यह संपूर्ण फ़ाइल को मेमोरी में पढ़ता है, जो फ़ाइल बड़ी होने पर समस्या हो सकती है।
jergason

22
@Jergason, यही वजह है कि उन्होंने अपना जवाब "अगर फ़ाइल बहुत बड़ी नहीं है ..." के साथ शुरू किया
laurent

9
ioutil को आयात किया जा सकता है"io/ioutil"
प्रमोद

7
नोट strings.Split जब नियमित POSIX पाठ फ़ाइलों को पार्स एक अतिरिक्त लाइन (एक खाली स्ट्रिंग) जोड़ देंगे, उदाहरण
बैन

1
FYI करें, विंडोज में, यह नहीं निकालेगा \r। तो आप \rहर तत्व के लिए एक जोड़ा हो सकता है ।
मैटफैक्स

32

पहले उत्तर को अपडेट नहीं किया जा सकता।
वैसे भी, Go1 रिलीज़ होने के बाद, कुछ टूटने वाले बदलाव हैं, इसलिए मैंने नीचे दिखाए अनुसार अपडेट किया:

package main

import (
    "os"
    "bufio"
    "bytes"
    "io"
    "fmt"
    "strings"
)

// Read a whole file into the memory and store it as array of lines
func readLines(path string) (lines []string, err error) {
    var (
        file *os.File
        part []byte
        prefix bool
    )
    if file, err = os.Open(path); err != nil {
        return
    }
    defer file.Close()

    reader := bufio.NewReader(file)
    buffer := bytes.NewBuffer(make([]byte, 0))
    for {
        if part, prefix, err = reader.ReadLine(); err != nil {
            break
        }
        buffer.Write(part)
        if !prefix {
            lines = append(lines, buffer.String())
            buffer.Reset()
        }
    }
    if err == io.EOF {
        err = nil
    }
    return
}

func writeLines(lines []string, path string) (err error) {
    var (
        file *os.File
    )

    if file, err = os.Create(path); err != nil {
        return
    }
    defer file.Close()

    //writer := bufio.NewWriter(file)
    for _,item := range lines {
        //fmt.Println(item)
        _, err := file.WriteString(strings.TrimSpace(item) + "\n"); 
        //file.Write([]byte(item)); 
        if err != nil {
            //fmt.Println("debug")
            fmt.Println(err)
            break
        }
    }
    /*content := strings.Join(lines, "\n")
    _, err = writer.WriteString(content)*/
    return
}

func main() {
    lines, err := readLines("foo.txt")
    if err != nil {
        fmt.Println("Error: %s\n", err)
        return
    }
    for _, line := range lines {
        fmt.Println(line)
    }
    //array := []string{"7.0", "8.5", "9.1"}
    err = writeLines(lines, "foo2.txt")
    fmt.Println(err)
}

18

आप उस के लिए bufio पैकेज के साथ os.File (जो io.Reader इंटरफ़ेस को लागू करता है) का उपयोग कर सकते हैं । हालांकि, उन पैकेजों को निश्चित मेमोरी उपयोग को ध्यान में रखते हुए बनाया जाता है (फाइल कितनी भी बड़ी क्यों न हो) और काफी तेज हैं।

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

package main

import (
    "os"
    "bufio"
    "bytes"
    "fmt"
)

// Read a whole file into the memory and store it as array of lines
func readLines(path string) (lines []string, err os.Error) {
    var (
        file *os.File
        part []byte
        prefix bool
    )
    if file, err = os.Open(path); err != nil {
        return
    }
    reader := bufio.NewReader(file)
    buffer := bytes.NewBuffer(make([]byte, 1024))
    for {
        if part, prefix, err = reader.ReadLine(); err != nil {
            break
        }
        buffer.Write(part)
        if !prefix {
            lines = append(lines, buffer.String())
            buffer.Reset()
        }
    }
    if err == os.EOF {
        err = nil
    }
    return
}

func main() {
    lines, err := readLines("foo.txt")
    if err != nil {
        fmt.Println("Error: %s\n", err)
        return
    }
    for _, line := range lines {
        fmt.Println(line)
    }
}

एक अन्य विकल्प io.ioutil.ReadAll का उपयोग करके एक ही बार में पूरी फ़ाइल में पढ़ा जा सकता है और लाइन द्वारा स्लाइस करना है। मैं आपको इस बात का स्पष्ट उदाहरण नहीं देता कि कैसे फ़ाइल में लाइनों को लिखा जाए, लेकिन यह मूल रूप os.Create()से उदाहरण में एक के समान लूप द्वारा पीछा किया जाता है (देखें main())।


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

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

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

2
ध्यान दें कि r58 (जुलाई 2011) के अनुसार, एन्कोडिंग / लाइन पैकेज को हटा दिया गया है। "इसकी कार्यक्षमता अब bufio में है।"
kristianp

4
func readToDisplayUsingFile1(f *os.File){
    defer f.Close()
    reader := bufio.NewReader(f)
    contents, _ := ioutil.ReadAll(reader)
    lines := strings.Split(string(contents), '\n')
}

या

func readToDisplayUsingFile1(f *os.File){
    defer f.Close()
    slice := make([]string,0)

    reader := bufio.NewReader(f)

    for{

    str, err := reader.ReadString('\n')
    if err == io.EOF{
        break
    }

        slice = append(slice, str)
    }

1
जितना अधिक "आधुनिक" हर कोई कहने की कोशिश करता रहता है, उतना ही यह 35 वर्षीय नंगे-न्यूनतम पुस्तकालय बाध्यकारी कोड जैसा दिखता है। : \ तथ्य यह है कि केवल एक लाइन-आधारित पाठ फ़ाइल को पढ़ने से ऐसी गड़बड़ी होती है जो केवल इस बात को पुष्ट करती है कि गो के पास एक लंबा रास्ता तय करना है .... जाओ ... और अधिक सामान्य उद्देश्य हो। पाठ का एक बहुत कुछ है, लाइन-आधारित डेटा वहाँ अभी भी बहुत कुशलता से अन्य langs और प्लेटफार्मों में संसाधित किया जा रहा है। $ .02
क्रिस जूल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.