2011-05-04 13 views
77

एक स्ट्रिंग सरणी में और बाहर एक टेक्स्ट फ़ाइल को पढ़ने (और लिखने) की क्षमता मुझे एक सामान्य आम आवश्यकता है। डेटाबेस को एक्सेस करने के लिए प्रारंभ में आवश्यकता को हटाने वाली भाषा से शुरू होने पर यह भी काफी उपयोगी होता है। क्या गोलांग में कोई अस्तित्व में है?
उदा। func ReadLines(sFileName string, iMinLines int) ([]string, bool) {
और func WriteLines(saBuff[]string, sFilename string) (bool) {
मैं डुप्लिकेट के बजाय मौजूदा एक का उपयोग करना पसंद करूंगा।स्ट्रिंग सरणी में टेक्स्ट फ़ाइल पढ़ें (और लिखें)

+2

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

उत्तर

84

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

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) 
    } 
} 
18

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

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

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() देखें)।

+0

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

+0

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

+0

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

30

पहला उत्तर अपडेट नहीं किया जा सकता है।

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) 
} 
+0

+1 इससे मुझे बहुत मदद मिली! धन्यवाद! – ximarin

102

तो फ़ाइल बहुत बड़ी नहीं है, यह ioutil.ReadFile और strings.Split कार्यों ताकि तरह से किया जा सकता:
वैसे भी, Go1 रिलीज होने के बाद, वहाँ कुछ टूटने परिवर्तन के रूप में नीचे दिखाया गया है, इसलिए मैं अद्यतन:

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

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

+0

यह समाधान दूसरों की तुलना में बहुत अधिक है, क्या कोई प्रदर्शन दंड है? –

+5

यह पूरी फ़ाइल को स्मृति में पढ़ता है, जो फ़ाइल बड़ी है, तो एक समस्या हो सकती है। – jergason

+13

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

2
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) 
    } 
संबंधित मुद्दे