2012-03-25 8 views
15

मुझे एक सरणी में पूर्णांक की एक फ़ाइल पढ़ने की जरूरत है। मैं इसे इस के साथ काम किया है:गोलांग, क्या एक सरणी में पूर्णांक की फ़ाइल पढ़ने का एक बेहतर तरीका है?

package main 

import (
    "fmt" 
    "io" 
    "os" 
) 

func readFile(filePath string) (numbers []int) { 
    fd, err := os.Open(filePath) 
    if err != nil { 
     panic(fmt.Sprintf("open %s: %v", filePath, err)) 
    } 
    var line int 
    for { 

     _, err := fmt.Fscanf(fd, "%d\n", &line) 

     if err != nil { 
      fmt.Println(err) 
      if err == io.EOF { 
       return 
      } 
      panic(fmt.Sprintf("Scan Failed %s: %v", filePath, err)) 

     } 
     numbers = append(numbers, line) 
    } 
    return 
} 

func main() { 
    numbers := readFile("numbers.txt") 
    fmt.Println(len(numbers)) 
} 

फ़ाइल numbers.txt बस है:

1 
2 
3 
... 

ReadFile() (शायद त्रुटि सौंपने की वजह से) बहुत लंबा लगता है।

क्या फ़ाइल लोड करने के लिए कोई छोटा/अधिक गो मूर्ख तरीका है?

+4

आप 'fd.Close() 'खो रहे हैं। 'Readfile' की पंक्ति दो के रूप में एक 'defer fd.Close()' जोड़ें। – Mostafa

+1

त्रुटि जांच के बाद 'defer fd.Close()' रखें। फ़ाइल पढ़ने में असफल होने पर आपको इस लाइन से रनटाइम पैनिक्स मिलेगा क्योंकि एफडी शून्य है। पहले त्रुटि की जांच करें, फिर अपने बंद को स्थगित करें। यदि आप खोलने में विफल रहे तो आपको वैसे भी बंद करने की आवश्यकता नहीं होगी। – burfl

+1

स्पष्टीकरण के लिए, ऐसा इसलिए है क्योंकि डिफर्स का तुरंत मूल्यांकन किया जाता है और बाद में निष्पादित किया जाता है। तो जब आप एक nil fd पर fd.Close() को स्थगित करने का प्रयास करते हैं (जिसमें कोई विधि नहीं है) तो आपको एक दहशत मिल जाएगी। 'एक्स: = 2; fmt.Print (x) defer; एक्स = 3 '2' प्रिंट होगा ', 3. – burfl

उत्तर

5

मैं इस तरह यह करना होगा:

package main 

import (
"fmt" 
    "io/ioutil" 
    "strconv" 
    "strings" 
) 

// It would be better for such a function to return error, instead of handling 
// it on their own. 
func readFile(fname string) (nums []int, err error) { 
    b, err := ioutil.ReadFile(fname) 
    if err != nil { return nil, err } 

    lines := strings.Split(string(b), "\n") 
    // Assign cap to avoid resize on every append. 
    nums = make([]int, 0, len(lines)) 

    for i, l := range lines { 
     // Empty line occurs at the end of the file when we use Split. 
     if len(l) == 0 { continue } 
     // Atoi better suits the job when we know exactly what we're dealing 
     // with. Scanf is the more general option. 
     n, err := strconv.Atoi(l) 
     if err != nil { return nil, err } 
     nums = append(nums, n) 
    } 

    return nums, nil 
} 

func main() { 
    nums, err := readFile("numbers.txt") 
    if err != nil { panic(err) } 
    fmt.Println(len(nums)) 
} 
+1

मेरी राय, "असाइन टोपी हर पर आकार बदलने संलग्न से बचने के लिए" में नहीं आकार बदलने से परहेज नहीं है, क्योंकि के आकार '[] स्ट्रिंग'' तार में कहीं छिपा हुआ है .Split'। –

+0

नहीं, 'तार। स्प्लिट' पहले 'सीपी' की घटनाओं की संख्या पाता है और आवंटन के लिए उस नंबर का उपयोग करता है। ['GenSplit'] देखें (http://code.google.com/p/go/source/browse/src/pkg/strings/strings.go#186)। – Mostafa

+0

दरअसल, लेकिन 'strings.Split' यह स्ट्रिंग के माध्यम से जा की कीमत पर दो बार कर रहा है - मुझे लगता है कि उम्मीद नहीं थी। किसी भी मामले में, यह सच नहीं है कि 'संलग्न' प्रत्येक परिशिष्ट पर आकार बदलता है। –

0

fmt.Fscanf साथ आपका समाधान ठीक है। यद्यपि आपकी स्थिति के आधार पर निश्चित रूप से करने के कई अन्य तरीके हैं। मुस्तफा की तकनीक एक मैं एक बहुत का उपयोग है (हालांकि मैं मेकअप के साथ एक बार में सभी परिणाम का आवंटन हो सकता है। उफ़! कि खरोंच। उन्होंने ऐसा किया।) लेकिन अंतिम नियंत्रण के लिए आप bufio.ReadLine सीखना चाहिए। कुछ उदाहरण कोड के लिए go readline -> string देखें।

15

bufio.Scanner का उपयोग करना चीजों को अच्छा बनाता है। मैंने फ़ाइल नाम लेने के बजाय io.Reader का भी उपयोग किया है। अक्सर कि, एक अच्छी तकनीक है, क्योंकि यह अनुमति देता है कोड पर किसी भी फ़ाइल जैसी वस्तु नहीं इस्तेमाल किया जाएगा और डिस्क पर सिर्फ एक फ़ाइल। यहां यह एक स्ट्रिंग से "पढ़ना" है।

package main 

import (
    "bufio" 
    "fmt" 
    "io" 
    "strconv" 
    "strings" 
) 

// ReadInts reads whitespace-separated ints from r. If there's an error, it 
// returns the ints successfully read so far as well as the error value. 
func ReadInts(r io.Reader) ([]int, error) { 
    scanner := bufio.NewScanner(r) 
    scanner.Split(bufio.ScanWords) 
    var result []int 
    for scanner.Scan() { 
     x, err := strconv.Atoi(scanner.Text()) 
     if err != nil { 
      return result, err 
     } 
     result = append(result, x) 
    } 
    return result, scanner.Err() 
} 

func main() { 
    tf := "1\n2\n3\n4\n5\n6" 
    ints, err := ReadInts(strings.NewReader(tf)) 
    fmt.Println(ints, err) 
} 
संबंधित मुद्दे