2014-01-14 1 views
8

Ich habe eine Textdatei, in der jede Zeile ein JSON-Objekt darstellt. Ich bin der Verarbeitung dieser Datei in Go mit einem einfachen for Schleife wie folgt aus:Wie liest man eine Textdatei Zeile für Zeile in Go, wenn einige Zeilen lang genug sind, um "bufio.Scanner: Token zu lange" Fehler zu verursachen?

scanner := bufio.NewScanner(file) 
for scanner.Scan() { 
    jsonBytes = scanner.Bytes() 
    var jsonObject interface{} 
    err := json.Unmarshal(jsonBytes, &jsonObject) 

    // do stuff with "jsonObject"... 

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

Wenn dieser Code eine Zeile mit einem besonders großen JSON-String (~ 67kb) erreicht, erhalte ich die Fehlermeldung „bufio.Scanner: Token zu lang ".

Gibt es eine einfache Möglichkeit, die maximale Zeilengröße, die von NewScanner gelesen werden kann, zu erhöhen? Oder gibt es einen anderen Ansatz, den Sie insgesamt machen können, wenn Sie Zeilen lesen müssen, die für NewScanner zu groß sind, aber im Allgemeinen bekannt sind, dass sie nicht von unsicherer Größe sind?

Antwort

13

Von the package docs:

Programme, die mehr Kontrolle über die Fehlerbehandlung oder große Token benötigen, oder müssen sequenziellen Scans auf einem Lesegerät ausführen, sollte bufio.Reader stattdessen verwenden.

Es sieht so aus, als wäre die bevorzugte Lösung bufio.Reader.ReadLine.

+3

Danke! Für jeden, der über diese Frage stolperte, habe ich den Code in dieser SO-Frage als Ausgangspunkt benutzt: http://stackoverflow.com/questions/6141604/go-readline-string. –

4

Sie wollen sicher nicht Zeile für Zeile lesen. Warum nicht Sie dies nur tun:

d := json.NewDecoder(file) 
for { 
    var ob whateverType 
    err := d.Decode(&ob) 
    if err == io.EOF { 
     break 
    } 
    if err != nil { 
     log.Fatalf("Error decoding: %v", err) 
    } 

    // do stuff with "jsonObject"... 

} 
+0

Würde dies gepuffert/Streaming-Eingang, obwohl? Ich bin zuversichtlich in der Annahme, dass ich nie eine einzelne Linie zu groß haben werde, um es Hauptspeicher zu passen. Ich bin jedoch ebenso zuversichtlich, dass die OVERALL FILE zu groß ist, um sie in einem Durchgang in den Hauptspeicher zu laden. –

+0

Sie sollten es versuchen. – Dustin

+2

Scheint gepuffert/streaming zu sein. Ich testete den Code mit 20 Zeilen und mit 400k Zeilen und der Speicherverbrauch war der gleiche (~ 4,5 mb) – freb

5

Sie können auch tun:

scanner := bufio.NewScanner(file) 
buf := make([]byte, 0, 64*1024) 
scanner.Buffer(buf, 1024*1024) 
for scanner.Scan() { 
    // do your stuff 
} 

Das zweite Argument für scanner.Buffer() setzt die maximale Token-Größe. Im obigen Beispiel können Sie die Datei scannen, solange keine Zeile größer als 1 MB ist.

Verwandte Themen