When writing programs, you often need to read data from one file and then output it to another file. The most typical example is to read from stdin and output to stdout. go provides several ways to read files, let's take a look one by one~
func fmtScan() { str := "" for { (&str) ("[]: %q (%d)\n", str, len(str)) } } // input: abc def ghi // output: //[]: "abc" (3) //[]: "def" (3) //[]: "ghi" (3)
Read data from stdin and output to memory variables. It will use the whitespace character as a split character character, and assign the divided string to the passed parameters in turn. In the above example, it is a cycle that is assigned to str three times respectively.
func osStdinRead() { p := make([]byte, 5) for { nn, err := (p) if err != nil && err != { panic(err) } ("[]: %q (%d)\n", p, nn) p = make([]byte, 5) // Clear p } } // input: abcdefghijk // output: //[]: "abcde" (5) //[]: "fghij" (5) //[]: "k\n\x00\x00\x00" (2)
Read up to len(p) size data. If the input content exceeds len(p), Read will continue to read in the next loop.
io series
ReadAll
func ioReadAll() { for { p, err := () if err != nil { panic(err) } ("[]: %q (%d)\n", p, len(p)) } } // input: abc\nEOF // output: []: "abc\n" (4)
ReadAll Reads everything and does not return EOF as an error.
ReadFull
func ioReadFull() { p := make([]byte, 5) for { nn, err := (, p) if err != nil && err != { ("[]: %q (%d)\n", p, nn) panic(err) } ("[]: %q (%d)\n", p, nn) p = make([]byte, 5) } } // input: aaaaaa // output: []: "aaaaa" (5) // input: aa\n\x00 // output: []: "aa\n\x00\x00" (3)
The goal of ReadFull is to fill p, which means that under normal circumstances, only the read data length nn==len(p) will be returned. There are two situations to note here:
- No data to be read, ReadFull returns (0, EOF)
- There is some data that is readable, but I encountered EOF before filling p, ReadFull returns (read length, ErrUnexpectedEOF)
bufio series
Bufio provides a buffer for io operations, avoiding access to disk every time.
Read
func bufioRead() { br := () p := make([]byte, 5) for { nn, err := (p) if err != nil && err != { panic(err) } ("[]: %q (%d)\n", p, nn) } } // input: abcdefghijk // output: //[]: "abcde" (5) //[]: "fghij" (5) //[]: "k\n\x00\x00\x00" (2)
Read up to len(p) size data. If the input content exceeds len(p), Read will continue to read in the next loop.
ReadBytes
func bufioReadBytes() { br := () for { p, err := ('\n') if err != nil && err != { panic(err) } ("[]: %q (%d)\n", p, len(p)) } } // input: abcdef // output: []: "abcdef\n" (7)
ReadBytes reads until the given delimiter is encountered, here is '\n' (the returned p contains \n). If err is encountered before reading the delimiter, the read data and err (usually EOF) are returned.
ReadString
func bufioReadString() { br := () for { str, err := ('\n') if err != nil && err != { panic(err) } ("[]: %q (%d)\n", str, len(str)) } } // input: abcdef // output: []: "abcdef\n" (7)
ReadString is similar to ReadBytes, both of which do not return until the delimiter is read.
ReadRune
func bufioReadRune() { br := () for { r, sz, err := () if err != nil && err != { panic(err) } ("[]: %q (%d)\n", r, sz) } } // input: abc // output: //[]: 'a' (1) //[]: 'b' (1) //[]: 'c' (1) //[]: '\n' (1)
ReadRune Reads one UTF8 character at a time.
Scan
func bufioScan() { scanner := () for () { text := () ("[]: %q (%d)\n", text, len(text)) } if () != nil { (().Error()) } }
Scan scans the file to the next token and returns true, and the token can then be read through Text, Bytes. When the scan stops, Scan returns false, and the error can be obtained through Err. If the scan stops because of EOF, Err=nil.
When creating scanner, ScanLines is used by default as the split function. It splits the input text into a series of lines, each line as a token. In addition, there are other segmentation functions:
-
ScanLines
(Default): Split by line. -
ScanWords
: Words divided by whitespace characters. -
ScanBytes
: Split by bytes. -
ScanRunes
: Segmented according to UTF-8 encoded characters.
Summarize
If you just read it from stdin, it is short enough and easy to use. When the file is large, it feels not very flexible when using it. It is recommended to use a series of methods of bufio.
This is the end of this article about how to read files in Go language. For more related Go files, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!