Home  >  Article  >  Backend Development  >  Idiom Go to read exactly N lines (instead of one byte) of text?

Idiom Go to read exactly N lines (instead of one byte) of text?

WBOY
WBOYforward
2024-02-09 08:40:09928browse

惯用语 Go 精确读取 N 行(而不是一个字节)的文本?

php editor Apple will introduce you to an idiom Go that accurately reads a specified number of lines (rather than one byte) of text. When working with text files, we often need to read a specific number of lines, rather than reading byte by byte. Using the bufio package of the Go language, we can easily achieve this goal. Next, we will detail how to use this idiom to achieve the function of accurately reading a specified number of lines of text. Let’s explore together!

Question content

I have a CSV from the report generator that has some non-CSV preamble added, for example:

Time Off Requests

My Org
Street Address
City, State  ZIP

Col1,Col2,Col3
r1c1,r1c2,r1c3
r2c1,r2c2,r2c3

I need to discard these 6 lines before passing the file's io.Reader to csv.NewReader and trying ReadAll(), so I need to make sure I don't read any bytes after line 6.

I originally thought of bufio.Scanner and calling Scan() 6 times in a loop, but then realized through experimentation that the "buf" in bufio means I have no control over where the buffered read ends, and it might read Past the real start position CSV.

So I figured out a way, which is to read byte by byte until I count 6 newlines (10):

f, _ := os.Open(csvPath)

// Read just past report-generated 6-line preamble
b := make([]byte, 1)
for i := 0; i < 6; {
    f.Read(b)
    if b[0] == 10 {
        i++
    }
}

r := csv.NewReader(f)
records, err = r.ReadAll()
...

This works. But is there a more idiomatic Go way?

Workaround

You don't need to avoid using bufio, in fact you should choose to use buffered IO whenever possible. What you can't do is use the original reader after accessing it via bufio.Reader, i.e. don't pass os.File after using bufio.NewReader To csv.NewReader, continue using bufio.Reader which may contain data that has been read from the file.

Once you have bufio.Reader, you can use all methods to read parts of the stream without worrying about reading byte by byte.

buf := bufio.NewReader(f)
// the preambled is defined as 6 lines
for i := 0; i < 6; i++ {
    line, err := buf.ReadBytes('\n')
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("line: %q\n", line)
}
r := csv.NewReader(buf)
records, err := r.ReadAll()
if err != nil {
    log.Fatal(err)
}
fmt.Printf("records: %q\n", records)

Complete example

The above is the detailed content of Idiom Go to read exactly N lines (instead of one byte) of text?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete