2016-09-19 9 views
0

私はGoを学び始めました。ioutil.ReadFile関数を使用すると、EOFが含まれているということに少し戸惑っています。たとえば、ファイルを読み込み、フィールドセパレータ上のすべての行を解析する必要があります。ReadFileまたはReadAllがEOFを読み取らないようにしてください

サンプル入力ファイル:これは私が読んで、そのファイルを解析するために何をすべきかです

CZG;KCZG;some text 
EKY;KEKY;some text 
A50;KA50;some text 
UKY;UCFL;some text 
MIC;KMIC;some text 
K2M;K23M;some text 

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

func main() { 
    /* Read file */ 
    airportsFile := "/path/to/file/ad_iata" 
    content, err := ioutil.ReadFile(airportsFile) 
    if err != nil { 
     log.Fatal(err) 
    } 

    /* split content on EOL */ 
    lines := strings.Split(string(content), "\n") 

    /* split line on field separator ; */ 
    for _, line := range lines { 
     lineSplit := strings.Split(line, ";") 
     fmt.Println(lineSplit) 
    } 
} 

string.Split機能がlineSplitスライスの最後に空の要素を追加したときに、それをEOF(解析するものはありません)が表示されます。したがって、そのスライス(lineSplit[1])の2番目のインデックスにアクセスする場合は、panic: runtime error: index out of rangeに移動します。私は実行して範囲を制限する必要があり、この

/* split line on field separator ; */ 
lenLines := len(lines) -1 
for _, line := range lines[:lenLines] { 
    lineSplit := strings.Split(line, ";") 
    fmt.Println(lineSplit[1]) 
} 

私はその簡潔さのためのReadFileを使用して保存しておきたい場合は、より良い方法はありますか? ioutil.ReadAll

答えて

4

「EOFバイト」または「EOF文字」などというものはありませんを使用している場合

同じ問題が発生します。あなたが見ているのはおそらく、ファイルの最後に改行文字('\n')があるためです。

行毎にファイルを読み込むために、それは代わりにbufio.Scannerを使用することがより慣用的です:Scannerはによって証明されるように、新しい行を開始せずに最後の改行が読み込まれますので、

file, err := os.Open(airportsFile) 
if err != nil { 
    log.Fatal(err) 
} 
defer file.Close() 

scanner := bufio.NewScanner(file) 
for scanner.Scan() { 
    line := scanner.Text() 
    // ... use line as you please ... 
} 

if err := scanner.Err(); err != nil { 
    log.Fatal(err) 
} 

そして、これは実際には、あなたの問題に対処しますthis playground example

+0

ファイルの末尾に '\ n'がありません。あなたのソリューションは 'bufio.Scanner'でうまく動作しますが、EOFが見えるときにioutil.ReadFileが空のスライスを追加しないようにするオプションがあるかどうかは不思議です。もし存在しなければ、bufioを使用します。ありがとう。 – ripat

+0

改行がないことをどのように確認しましたか?編集者の中には、これらを実際には空白行として表示するのではなく、とにかく静かに追加する編集者もいます。 'od -tc/path/to/file/ad_iata'を試してみてください。 – Thomas

+0

私は訂正しました。最後の行の最後には '\ n'という末尾があります。これにより、 'ioutil.ReadFile'の動作が私にとってより論理的になります。私はあなたから何かを学んだ。再度、感謝します。 – ripat

1

scanner.Err()を使用して、ファイルの読み取り時のエラーをチェックできます。一般的に

// Err returns the first non-EOF error that was encountered by the Scanner. 
func (s *Scanner) Err() error { 
    if s.err == io.EOF { 
     return nil 
    } 
    return s.err 
} 

ファイルを読み込んで解析する慣用的な方法を読み、新しいScannerを返すために、入力パラメータとしてファイルを受け入れたbufio.NewScannerを使用することです行くインチここでは上記の発言を考慮

は、ファイルを読み込んで解析することができる方法である。

package main 

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

func main() { 
    input, err := os.Open("example.txt") 

    if err != nil { 
     panic("Error happend during opening the file. Please check if file exists!") 
     os.Exit(1) 
    } 

    defer input.Close() 

    scanner := bufio.NewScanner(input) 
    for scanner.Scan() { 
     line := scanner.Text() 
     fmt.Printf("%v\n", line) 
    } 
    if err := scanner.Err(); err != nil { 
     fmt.Fprintln(os.Stderr, "reading input:", err) 
    }  
} 
2

あなたの入力ファイルは、CSVファイルであることをseeems、あなたが見えたencoding/csv

airportsFile := "/path/to/file/ad_iata" 
content, err := os.Open(airportsFile) 
    if err != nil { 
     log.Fatal(err) 
    } 
r := csv.NewReader(content) 
r.Comma = ';' 
records, err := r.ReadAll() /* split line on field separator ; */ 
if err != nil { 
    log.Fatal(err) 
} 
fmt.Println(records) 

を使用することができます私にとって十分に合い、正しい出力を提供します。

[[CZG KCZG some text] [EKY KEKY some text] [A50 KA50 some text] [UKK UCFL some text] [KM2] M K23M some text]]

関連する問題