Different methods to read multiple lines from STDIN
In this article, I will demonstrate multiline input in a Go terminal application. In the previous article, we discussed about how to parse multiple inputs from users in Golang. Now, we are going to introduce 3 methods to read multiple lines from the console:
fmt.Scan()
bufio.Reader()
bufio.Scanner()
Method-1: Use fmt.Scan()Â to read multiple lines of text
func Scan(a ...any) (n int, err error)
: Scan scans text read from standard input, storing successive space-separated values into successive arguments. Newlines count as space. It returns the number of items successfully scanned.
In the example below, we use the Scan()
function to read 3 lines from stdin and save each line as a variable.
package main
import (
"fmt"
"log"
)
func main() {
fmt.Println("input text:")
var line1, line2, line3 string
_, err := fmt.Scan(&line1, &line2, &line3)
if err != nil {
log.Fatal(err)
}
fmt.Printf("3 lines of text: %s %s %s\n", line1, line2, line3)
}
Output:
input text:
line1
line2
line3
3 lines of text: line1 line2 line3
Note that the Scan()
function considers newlines as spaces, so each line cannot contain space characters.
Method-2: Use bufio.Reader to read multiple lines of text
func (b *Reader) ReadString(delim byte) (string, error)
: ReadString reads until the first occurrence of delim in the input, returning a string containing the data up to and including the delimiter. If ReadString encounters an error before finding a delimiter, it returns the data read before the error and the error itself (often io.EOF).
We will show you an example of using ReadString()
to input multiple lines of text until the line only contains space characters.
package main
import (
"bufio"
"fmt"
"log"
"os"
"strings"
)
func main() {
fmt.Println("input text:")
reader := bufio.NewReader(os.Stdin)
var lines []string
for {
// read line from stdin using newline as separator
line, err := reader.ReadString('\n')
if err != nil {
log.Fatal(err)
}
// if line is empty, break the loop
if len(strings.TrimSpace(line)) == 0 {
break
}
//append the line to a slice
lines = append(lines, line)
}
//print out all the lines
println(len(lines))
fmt.Println("output:")
for _, eachLine := range lines {
fmt.Println(eachLine)
}
}
Output:
input text:
This is GoLinuxCloud
Welcome to our website
output:
This is GoLinuxCloud
Welcome to our website
Note that the ReadString()
function returns a string containing the data up to and including the delimiter, so all the lines will contain '\n
' at the end of line.
Method-3: Use bufio.Scanner to read multiple lines of text until the empty line
func (s *Scanner) Text() string
: Text returns the most recent token generated by a call to Scan as a newly allocated string holding its bytes.
Here is an example of using Scanner()
to input multiple lines of text until the input line is empty.
package main
import (
"bufio"
"fmt"
"log"
"os"
)
func main() {
fmt.Println("input text:")
scanner := bufio.NewScanner(os.Stdin)
var lines []string
for {
scanner.Scan()
line := scanner.Text()
// break the loop if line is empty
if len(line) == 0 {
break
}
lines = append(lines, line)
}
err := scanner.Err()
if err != nil {
log.Fatal(err)
}
fmt.Println("output:")
for _, eachLine := range lines {
fmt.Println(eachLine)
}
}
Output:
input text:
Today is Sunday
Have a nice weekend!
output:
Today is Sunday
Have a nice weekend!
Read multiple lines of text from STDIN conditionally
We can modify the code from Section 3 to read lines from the console and add a condition to read until it reaches a line that only contains the 'Q' character.
package main
import (
"bufio"
"fmt"
"log"
"os"
"strings"
)
func main() {
fmt.Println("input text:")
scanner := bufio.NewScanner(os.Stdin)
var lines []string
for {
scanner.Scan()
line := scanner.Text()
// break the loop if line is contains 'q' only
if strings.ToLower(strings.TrimSpace(line)) == "q" {
break
}
lines = append(lines, line)
}
err := scanner.Err()
if err != nil {
log.Fatal(err)
}
fmt.Println("output:")
for _, eachLine := range lines {
fmt.Println(eachLine)
}
}
Output:
input text:
Hello
This is our website
Q
output:
Hello
This is our website
Summary
There are some ways to input multiple lines from console in Golang
- Using the
fmt.Scan()
in case reading multiple words where each word is on a separate line. - Using the
bufio.Reader
in case reading multiple lines together with the newline character at the end of each line. - Using bufio.Scanner, which allows us to get a list of input lines without the newline character at the end of each line, is the most recommended and universal method of reading multiple lines.
References
https://pkg.go.dev/bufio#Scanner.Scan
https://pkg.go.dev/fmt#Scan