Ich kann nicht finden file.ReadLine
Funktion in Go.
Wie kann man eine Datei Zeile für Zeile lesen?
Ich kann nicht finden file.ReadLine
Funktion in Go.
Wie kann man eine Datei Zeile für Zeile lesen?
In Go 1.1 und neuer ist der einfachste Weg, dies zu tun, mit einer bufio.Scanner
. Hier ist ein einfaches Beispiel, das Zeilen aus einer Datei liest:
package main
import (
"bufio"
"fmt"
"log"
"os"
)
func main() {
file, err := os.Open("/path/to/file.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
// optionally, resize scanner's capacity for lines over 64K, see next example
for scanner.Scan() {
fmt.Println(scanner.Text())
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
}
Dies ist der sauberste Weg, um aus einer Reader
Zeile für Zeile.
Es gibt eine Einschränkung: Bei Zeilen, die länger als 65536 Zeichen sind, macht der Scanner einen Fehler. Wenn Sie wissen, dass Ihre Zeilenlänge größer als 64K ist, verwenden Sie die Buffer()
Methode, um die Kapazität des Scanners zu erhöhen:
...
scanner := bufio.NewScanner(file)
const maxCapacity int = longLineLen // your required line length
buf := make([]byte, maxCapacity)
scanner.Buffer(buf, maxCapacity)
for scanner.Scan() {
...
Und da der Auftraggeber darum bat, eine Datei zu überprüfen, wäre es trivial, zunächst file, _ := os.Open("/path/to/file.csv")
und scannen Sie dann den Dateihandle: scanner := bufio.NewScanner(file)
Das Problem ist, dass Scanner.Scan() auf eine Puffergröße von 4096 []Byte pro Zeile beschränkt ist. Sie erhalten bufio.ErrTooLong
Fehler, der bufio.Scanner: token too long
wenn die Schlange zu lang ist. In diesem Fall müssen Sie bufio.ReaderLine() oder ReadString() verwenden.
HINWEIS: Die akzeptierte Antwort war in frühen Versionen von Go richtig. Siehe die höchstbewertete Antwort enthält den neueren idiomatischen Weg, dies zu erreichen.
Es gibt eine Funktion ReadLine im Paket bufio
.
Bitte beachten Sie, dass die Funktion eine unvollständige Zeile zurückgibt, wenn die Zeile nicht in den Lesepuffer passt. Wenn Sie in Ihrem Programm immer eine ganze Zeile mit einem einzigen Funktionsaufruf lesen wollen, müssen Sie die ReadLine
Funktion in Ihre eigene Funktion, die die ReadLine
in einer for-Schleife.
bufio.ReadString('\n')
nicht vollständig gleichwertig ist mit ReadLine
denn ReadString
ist nicht in der Lage, den Fall zu behandeln, dass die letzte Zeile einer Datei nicht mit dem Zeilenumbruchzeichen endet.
Aus den Unterlagen: "ReadLine ist ein primitives Zeilenleseprogramm auf niedriger Ebene. Die meisten Aufrufer sollten ReadBytes(') verwenden. \n ') oder ReadString(' \n ') oder verwenden Sie einen Scanner."
@mdwhatcott Warum spielt es eine Rolle, dass es sich um ein "Low-Level-Line-Reading-Primitiv" handelt? Wie kommt man zu dem Schluss, dass "die meisten Aufrufer ReadBytes(') verwenden sollten? \n ') oder ReadString(' \n ') oder verwenden Sie einen Scanner."?
@CharlieParker - Ich bin mir nicht sicher, ich zitiere nur aus den Unterlagen, um den Kontext zu verdeutlichen.
Ich habe eine Methode entwickelt, mit der man jede Zeile aus einer Datei lesen kann. Die Funktion Readln(*bufio.Reader) gibt eine Zeile zurück (ohne \n ) aus der zugrunde liegenden bufio.Reader-Struktur.
// Readln returns a single line (without the ending \n)
// from the input buffered reader.
// An error is returned iff there is an error with the
// buffered reader.
func Readln(r *bufio.Reader) (string, error) {
var (isPrefix bool = true
err error = nil
line, ln []byte
)
for isPrefix && err == nil {
line, isPrefix, err = r.ReadLine()
ln = append(ln, line...)
}
return string(ln),err
}
Sie können Readln verwenden, um jede Zeile einer Datei zu lesen. Der folgende Code liest jede Zeile in einer Datei und gibt jede Zeile auf stdout aus.
f, err := os.Open(fi)
if err != nil {
fmt.Printf("error opening file: %v\n",err)
os.Exit(1)
}
r := bufio.NewReader(f)
s, e := Readln(r)
for e == nil {
fmt.Println(s)
s,e = Readln(r)
}
Zum Wohl!
Ich habe diese Antwort geschrieben, bevor Go 1.1 herauskam. Go 1.1 hat ein Scanner-Paket in der stdlib., die die gleiche Funktionalität wie meine Antwort bietet. Ich würde empfehlen, Scanner anstelle meiner Antwort zu verwenden, da Scanner in der stdlib. enthalten ist. Viel Spaß beim Hacken! :-)
Es gibt zwei gängige Methoden, um eine Datei Zeile für Zeile zu lesen.
In meinem Testfall, ~250MB, ~2.500.000 Zeilen bufio.Scanner(Zeitaufwand: 0.395491384s) ist schneller als bufio.Reader.ReadString(Zeitaufwand: 0.446867622s).
Quellcode: https://github.com/xpzouying/go-practice/tree/master/read_file_line_by_line
Datei lesen mit bufio.Scanner,
func scanFile() {
f, err := os.OpenFile(logfile, os.O_RDONLY, os.ModePerm)
if err != nil {
log.Fatalf("open file error: %v", err)
return
}
defer f.Close()
sc := bufio.NewScanner(f)
for sc.Scan() {
_ = sc.Text() // GET the line string
}
if err := sc.Err(); err != nil {
log.Fatalf("scan file error: %v", err)
return
}
}
Datei lesen mit bufio.Reader,
func readFileLines() {
f, err := os.OpenFile(logfile, os.O_RDONLY, os.ModePerm)
if err != nil {
log.Fatalf("open file error: %v", err)
return
}
defer f.Close()
rd := bufio.NewReader(f)
for {
line, err := rd.ReadString('\n')
if err != nil {
if err == io.EOF {
break
}
log.Fatalf("read file line error: %v", err)
return
}
_ = line // GET the line string
}
}
Beachten Sie, dass diese bufio.Reader
Beispiel liest die letzte Zeile einer Datei nicht, wenn sie nicht mit einem Zeilenumbruch endet. ReadString
gibt sowohl die letzte Zeile als auch io.EOF
in diesem Fall.
Beispiel aus diesem .
func readLine(path string) {
inFile, err := os.Open(path)
if err != nil {
fmt.Println(err.Error() + `: ` + path)
return
}
defer inFile.Close()
scanner := bufio.NewScanner(inFile)
for scanner.Scan() {
fmt.Println(scanner.Text()) // the line
}
}
aber dies führt zu einem Fehler, wenn eine Zeile größer als der Puffer des Scanners ist.
Wenn das passiert ist, benutze ich Folgendes reader := bufio.NewReader(inFile)
meinen eigenen Puffer zu erstellen und zu verketten, entweder mit ch, err := reader.ReadByte()
ou len, err := reader.Read(myBuffer)
Eine andere Methode, die ich verwende (ersetzen Sie os.Stdin mit Datei wie oben), diese konkaten, wenn Zeilen lang sind (isPrefix) und ignoriert leere Zeilen:
func readLines() []string {
r := bufio.NewReader(os.Stdin)
bytes := []byte{}
lines := []string{}
for {
line, isPrefix, err := r.ReadLine()
if err != nil {
break
}
bytes = append(bytes, line...)
if !isPrefix {
str := strings.TrimSpace(string(bytes))
if len(str) > 0 {
lines = append(lines, str)
bytes = []byte{}
}
}
}
if len(bytes) > 0 {
lines = append(lines, string(bytes))
}
return lines
}
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.
9 Stimmen
Ab Go1.1 ist bufio.Scanner die beste Möglichkeit, dies zu tun.