답변:
참고 : 허용되는 답변은 초기 버전의 Go에서 정확했습니다. 가장 높은 투표 답변을 보려면 최신 관용적 방법이 포함되어 있습니다.
package에 ReadLine 함수가 있습니다 bufio.
행이 읽기 버퍼에 맞지 않으면이 함수는 불완전한 행을 반환합니다. 함수를 한 번만 호출하여 프로그램의 전체 행을 항상 읽으려면 for 루프 ReadLine를 호출 하는 함수를 함수에 캡슐화해야합니다 ReadLine.
bufio.ReadString('\n')파일의 마지막 행이 개행 문자로 끝나지 않는 경우를 처리 할 수 ReadLine없기 때문에 완전히 동일 ReadString하지 않습니다.
Go 1.1 이상에서 가장 간단한 방법은을 사용하는 것 bufio.Scanner입니다. 다음은 파일에서 행을 읽는 간단한 예입니다.
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)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
}
이것은 한 Reader줄씩 읽는 가장 깨끗한 방법 입니다.
한 가지주의 사항이 있습니다. 스캐너는 65536자를 초과하는 행을 제대로 처리하지 못합니다. 그것이 당신에게 문제라면, 아마도 당신은 위에 자신을 굴려야 할 것입니다 Reader.Read().
file, _ := os.Open("/path/to/file.csv")파일 핸들 을 먼저 스캔 한 다음 스캔하는 것이 쉽지 않습니다 .scanner := bufio.NewScanner(file)
defer file.Close().
bufio.ErrTooLong인 오류를 bufio.Scanner: token too long줄이 너무 긴 경우. 이 경우 bufio.ReaderLine () 또는 ReadString ()을 사용해야합니다.
사용하다:
reader.ReadString('\n')
\n반환 된 문자열의 끝에를 유지합니다 .reader.ReadLine()
다른 답변에서 문제로 식별되는 시나리오를 테스트하는 프로그램을 작성하여 제안 된 다양한 솔루션을 테스트했습니다.
나는 그것을 발견했다 :
Scanner솔루션은 긴 줄을 처리하지 않습니다.ReadLine솔루션은 구현하기가 복잡하다.ReadString솔루션은 간단하고 긴 줄을 작동합니다.각 솔루션을 보여주는 코드는 다음과 같습니다 go run main.go.
package main
import (
"bufio"
"bytes"
"fmt"
"io"
"os"
)
func readFileWithReadString(fn string) (err error) {
fmt.Println("readFileWithReadString")
file, err := os.Open(fn)
defer file.Close()
if err != nil {
return err
}
// Start reading from the file with a reader.
reader := bufio.NewReader(file)
var line string
for {
line, err = reader.ReadString('\n')
fmt.Printf(" > Read %d characters\n", len(line))
// Process the line here.
fmt.Println(" > > " + limitLength(line, 50))
if err != nil {
break
}
}
if err != io.EOF {
fmt.Printf(" > Failed!: %v\n", err)
}
return
}
func readFileWithScanner(fn string) (err error) {
fmt.Println("readFileWithScanner - this will fail!")
// Don't use this, it doesn't work with long lines...
file, err := os.Open(fn)
defer file.Close()
if err != nil {
return err
}
// Start reading from the file using a scanner.
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
fmt.Printf(" > Read %d characters\n", len(line))
// Process the line here.
fmt.Println(" > > " + limitLength(line, 50))
}
if scanner.Err() != nil {
fmt.Printf(" > Failed!: %v\n", scanner.Err())
}
return
}
func readFileWithReadLine(fn string) (err error) {
fmt.Println("readFileWithReadLine")
file, err := os.Open(fn)
defer file.Close()
if err != nil {
return err
}
// Start reading from the file with a reader.
reader := bufio.NewReader(file)
for {
var buffer bytes.Buffer
var l []byte
var isPrefix bool
for {
l, isPrefix, err = reader.ReadLine()
buffer.Write(l)
// If we've reached the end of the line, stop reading.
if !isPrefix {
break
}
// If we're just at the EOF, break
if err != nil {
break
}
}
if err == io.EOF {
break
}
line := buffer.String()
fmt.Printf(" > Read %d characters\n", len(line))
// Process the line here.
fmt.Println(" > > " + limitLength(line, 50))
}
if err != io.EOF {
fmt.Printf(" > Failed!: %v\n", err)
}
return
}
func main() {
testLongLines()
testLinesThatDoNotFinishWithALinebreak()
}
func testLongLines() {
fmt.Println("Long lines")
fmt.Println()
createFileWithLongLine("longline.txt")
readFileWithReadString("longline.txt")
fmt.Println()
readFileWithScanner("longline.txt")
fmt.Println()
readFileWithReadLine("longline.txt")
fmt.Println()
}
func testLinesThatDoNotFinishWithALinebreak() {
fmt.Println("No linebreak")
fmt.Println()
createFileThatDoesNotEndWithALineBreak("nolinebreak.txt")
readFileWithReadString("nolinebreak.txt")
fmt.Println()
readFileWithScanner("nolinebreak.txt")
fmt.Println()
readFileWithReadLine("nolinebreak.txt")
fmt.Println()
}
func createFileThatDoesNotEndWithALineBreak(fn string) (err error) {
file, err := os.Create(fn)
defer file.Close()
if err != nil {
return err
}
w := bufio.NewWriter(file)
w.WriteString("Does not end with linebreak.")
w.Flush()
return
}
func createFileWithLongLine(fn string) (err error) {
file, err := os.Create(fn)
defer file.Close()
if err != nil {
return err
}
w := bufio.NewWriter(file)
fs := 1024 * 1024 * 4 // 4MB
// Create a 4MB long line consisting of the letter a.
for i := 0; i < fs; i++ {
w.WriteRune('a')
}
// Terminate the line with a break.
w.WriteRune('\n')
// Put in a second line, which doesn't have a linebreak.
w.WriteString("Second line.")
w.Flush()
return
}
func limitLength(s string, length int) string {
if len(s) < length {
return s
}
return s[:length]
}
나는 테스트했다 :
테스트 프로그램은 다음을 출력합니다.
Long lines
readFileWithReadString
> Read 4194305 characters
> > aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
> Read 12 characters
> > Second line.
readFileWithScanner - this will fail!
> Failed!: bufio.Scanner: token too long
readFileWithReadLine
> Read 4194304 characters
> > aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
> Read 12 characters
> > Second line.
No linebreak
readFileWithReadString
> Read 28 characters
> > Does not end with linebreak.
readFileWithScanner - this will fail!
> Read 28 characters
> > Does not end with linebreak.
readFileWithReadLine
> Read 28 characters
> > Does not end with linebreak.
defer file.Close()에러 체크 한 후해야한다; 그렇지 않으면 오류가 발생하면 패닉 상태가됩니다.
파일에서 각 줄을 쉽게 읽을 수있는 방법을 작성했습니다. Readln (* bufio.Reader) 함수는 기본 bufio.Reader 구조체에서 행 (sans \ n)을 반환합니다.
// 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
}
Readln을 사용하여 파일에서 모든 행을 읽을 수 있습니다. 다음 코드는 파일의 모든 줄을 읽고 각 줄을 stdout으로 출력합니다.
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)
}
건배!
파일을 한 줄씩 읽는 두 가지 일반적인 방법이 있습니다.
내 테스트 사례 에서 ~ 250MB, ~ 2,500,000 줄 , bufio.Scanner (사용 시간 : 0.395491384s)가 bufio.Reader.ReadString (time_used : 0.446867622s)보다 빠릅니다.
소스 코드 : https://github.com/xpzouying/go-practice/tree/master/read_file_line_by_line
파일 사용 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
}
}
읽기 파일 사용 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
}
}
bufio.Reader예제는 줄 바꿈으로 끝나지 않으면 파일의 마지막 줄을 읽지 않습니다. ReadString마지막 줄 io.EOF과이 경우 모두 반환합니다 .
이 요지의 예
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
}
}
그러나 이것은 스캐너 버퍼보다 큰 행이있을 때 오류를 발생시킵니다.
그 일이 때, 내가하는 일은 사용이 reader := bufio.NewReader(inFile)만들어 내 자신의 버퍼 CONCAT 사용하거나 ch, err := reader.ReadByte()또는len, err := reader.Read(myBuffer)
내가 사용하는 또 다른 방법은 (os.Stdin을 위와 같은 파일로 대체) 줄이 길 때 (isPrefix) 연결되고 빈 줄을 무시합니다.
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
}
-1할까?
\ n과 함께 ReadString을 구분 기호로 사용할 수도 있습니다.
f, err := os.Open(filename)
if err != nil {
fmt.Println("error opening file ", err)
os.Exit(1)
}
defer f.Close()
r := bufio.NewReader(f)
for {
path, err := r.ReadString(10) // 0x0A separator = newline
if err == io.EOF {
// do something here
break
} else if err != nil {
return err // if you return error
}
}
bufio.Reader.ReadLine () 이 잘 작동합니다. 그러나 문자열로 각 줄을 읽으려면 ReadString ( '\ n')을 사용하십시오 . 바퀴를 재발 명할 필요는 없습니다.
// strip '\n' or read until EOF, return error if read error
func readline(reader io.Reader) (line []byte, err error) {
line = make([]byte, 0, 100)
for {
b := make([]byte, 1)
n, er := reader.Read(b)
if n > 0 {
c := b[0]
if c == '\n' { // end of line
break
}
line = append(line, c)
}
if er != nil {
err = er
return
}
}
return
}
아래 코드에서 사용자가 Enter 키를 누르고 Readline을 사용할 때까지 CLI에서 관심 사항을 읽습니다.
interests := make([]string, 1)
r := bufio.NewReader(os.Stdin)
for true {
fmt.Print("Give me an interest:")
t, _, _ := r.ReadLine()
interests = append(interests, string(t))
if len(t) == 0 {
break;
}
}
fmt.Println(interests)
나는 Lzap 솔루션을 좋아하고, Go에서 새로 왔으며, lzap에게 물어보고 싶지만 아직 50 포인트가 없었습니다. 나는 약간의 솔루션을 변경하고 코드를 완성합니다 ...
package main
import (
"bufio"
"fmt"
"io"
"os"
)
func main() {
f, err := os.Open("archiveName")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer f.Close()
r := bufio.NewReader(f)
line, err := r.ReadString(10) // line defined once
for err != io.EOF {
fmt.Print(line) // or any stuff
line, err = r.ReadString(10) // line was defined before
}
}
왜 'err'를 다시 테스트해야하는지 잘 모르겠지만 어쨌든 우리는 할 수 있습니다. 그러나 주요 질문은 .. 왜 루프 내부에서 문장 => 줄, err : = r.ReadString (10)에 오류가 발생하지 않습니까? 루프가 실행될 때마다 반복해서 정의됩니다. 나는 그 변화, 의견이있는 상황을 피할 수 있습니까? 나는 'for'에서 조건 EOF를 While과 비슷하게 설정했습니다. 감사
import (
"bufio"
"os"
)
var (
reader = bufio.NewReader(os.Stdin)
)
func ReadFromStdin() string{
result, _ := reader.ReadString('\n')
witl := result[:len(result)-1]
return witl
}
다음 ReadFromStdin()과 같은 함수를 가진 예제가 fmt.Scan(&name)있지만 "Hello My Name Is ..."와 같이 공백이있는 모든 문자열을 사용합니다.
var name string = ReadFromStdin()
println(name)