Reading input in Go is essential for creating interactive programs.
Go provides several ways to read input from different sources, such as from the command line, from files, or directly from the console.
The fmt, bufio, and os packages are commonly used to read input in various formats.
In this tutorial, we’ll cover:
1. Reading Input with fmt.Scan
The fmt.Scan function reads input from the standard input (console). It scans text into the specified variables and stops reading when it encounters whitespace.
package main import "fmt" func main() { var name string var age int fmt.Print("Enter your name and age: ") fmt.Scan(&name, &age) // Read values from user input fmt.Println("Name:", name) fmt.Println("Age:", age) }
Input:
Alice 30
Output:
Name: Alice Age: 30
In this example:
- fmt.Scan(&name, &age) reads two values (a string and an int) and stores them in name and age, respectively.
- fmt.Scan stops reading when it encounters whitespace, making it suitable for reading space-separated values.
2. Reading Input with fmt.Scanf
The fmt.Scanf function reads formatted input based on a specified format string. It allows you to control the input format and read specific types of data.
package main import "fmt" func main() { var name string var age int fmt.Print("Enter your name and age (e.g., 'Alice 30'): ") fmt.Scanf("%s %d", &name, &age) // Specify format to read name and age fmt.Println("Name:", name) fmt.Println("Age:", age) }
Input:
Alice 30
Output:
Name: Alice Age: 30
In this example:
- fmt.Scanf(“%s %d”, &name, &age) uses the format string %s %d to specify the expected input format (string followed by integer).
- fmt.Scanf is useful when you need more control over the input format.
3. Reading Entire Lines with bufio.Reader
The bufio.Reader provides a way to read entire lines, including spaces. This approach is useful for reading sentences or phrases that contain spaces.
package main import ( "bufio" "fmt" "os" ) func main() { reader := bufio.NewReader(os.Stdin) fmt.Print("Enter your full name: ") name, _ := reader.ReadString('\n') // Read until newline character fmt.Println("Your name is:", name) }
Input:
Alice Johnson
Output:
Your name is: Alice Johnson
In this example:
- reader.ReadString(‘\n') reads input until it encounters a newline character.
- bufio.Reader is ideal for reading entire lines of text, including whitespace.
4. Reading Input from Command-Line Arguments
Command-line arguments are passed to the program when it starts. The os.Args slice provides access to these arguments, with the first element being the program name.
package main import ( "fmt" "os" ) func main() { if len(os.Args) < 3 { fmt.Println("Usage: go run main.go <name> <age>") return } name := os.Args[1] age := os.Args[2] fmt.Println("Name:", name) fmt.Println("Age:", age) }
Run the program with:
go run main.go Alice 30
Output:
Name: Alice Age: 30
In this example:
- os.Args[1] and os.Args[2] access the command-line arguments after the program name.
- The program requires at least two arguments (name and age) and prints an error message if they are missing.
5. Reading Input from Files
To read data from a file, use the os.Open function to open the file, and bufio.NewScanner or bufio.Reader to read its contents.
Using bufio.Scanner
package main import ( "bufio" "fmt" "os" ) func main() { file, err := os.Open("input.txt") if err != nil { fmt.Println("Error opening file:", err) return } defer file.Close() scanner := bufio.NewScanner(file) for scanner.Scan() { line := scanner.Text() fmt.Println(line) } if err := scanner.Err(); err != nil { fmt.Println("Error reading file:", err) } }
Assuming input.txt contains:
Hello, World! Welcome to Go programming.
Output:
Hello, World! Welcome to Go programming.
In this example:
- bufio.NewScanner(file) reads the file line by line.
- scanner.Scan() advances the scanner to the next line, and scanner.Text() returns the current line.
Using ioutil.ReadFile
If you want to read the entire file at once, use ioutil.ReadFile, which returns the file contents as a byte slice.
package main import ( "fmt" "io/ioutil" ) func main() { data, err := ioutil.ReadFile("input.txt") if err != nil { fmt.Println("Error reading file:", err) return } fmt.Println("File contents:\n", string(data)) }
Output:
File contents: Hello, World! Welcome to Go programming.
In this example:
- ioutil.ReadFile(“input.txt”) reads the entire file into data.
- string(data) converts the byte slice to a string for printing.
Note: ioutil.ReadFile reads the entire file into memory, so it’s best used for smaller files.
6. Best Practices for Reading Input in Go
a) Use fmt.Scan and fmt.Scanf for Simple Input
For reading simple values (like numbers and single words), fmt.Scan and fmt.Scanf are efficient and concise.
var name string fmt.Scan(&name)
b) Use bufio.Reader for Reading Full Lines
For multi-word input or longer strings, use bufio.Reader to read complete lines.
reader := bufio.NewReader(os.Stdin) line, _ := reader.ReadString('\n')
c) Validate Command-Line Arguments
When using os.Args, always check the length of arguments to avoid runtime errors.
if len(os.Args) < 3 { fmt.Println("Usage: go run main.go <name> <age>") return }
d) Handle Errors Gracefully
Handle potential errors when reading input, especially with files, to improve program reliability.
if err := scanner.Err(); err != nil { fmt.Println("Error reading file:", err) }
e) Use defer to Close Files
Always use defer to ensure that files are closed after reading to avoid resource leaks.
file, err := os.Open("input.txt") if err != nil { fmt.Println("Error:", err) return } defer file.Close()
Summary
In this tutorial, we covered the basics of reading input in Go:
- Reading Input with fmt.Scan: Reading space-separated values into variables.
- Reading Input with fmt.Scanf: Using formatted input for structured data.
- Reading Entire Lines with bufio.Reader: Handling multi-word input and full lines.
- Reading Input from Command-Line Arguments: Accessing command-line parameters with os.Args.
- Reading Input from Files: Using bufio.Scanner and ioutil.ReadFile to read files.
- Best Practices for Reading Input: Tips for writing clean, error-free input handling code.
Understanding how to read input is crucial for building interactive applications and data-driven programs in Go. Each method has its ideal use cases, so choosing the right approach based on your needs will help make your code cleaner and more efficient.