Skip to content

Input and Output ​

Before You Start

  • Applies to: Go 1.21+ (examples verified with Go 1.22) · Prerequisites: Basic Syntax · Read time: about 10 min
go
package main

import "fmt"

func main() {
   fmt.Println("Hello 世界!")
}

The first introductory example on this site was outputting a string. This section explains how to perform input and output in Go.

File Descriptors ​

go
var (
   Stdin  = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
   Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
   Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr")
)

In the os package, there are three externally exposed file descriptors, all of type *os.File:

  • os.Stdin - Standard Input
  • os.Stdout - Standard Output
  • os.Stderr - Standard Error

Input and output in Go are all done through these.

Output ​

There are many ways to output in Go. Here are some common ones:

stdout ​

Since standard output is itself a file, you can directly write strings to standard output:

go
package main

import "os"

func main() {
  os.Stdout.WriteString("hello world!")
}

print ​

Go has two built-in functions, print and println. They output parameters to standard error and are only used for debugging. They are generally not recommended.

go
package main

func main() {
  print("hello world!\n")
  println("hello world")
}

fmt ​

The most common usage is to use the fmt package. It provides the fmt.Println function, which outputs parameters to standard output by default.

go
package main

import "fmt"

func main() {
  fmt.Println("hello world!")
}

It accepts parameters of any type. If the type implements the String interface, it will call the String method to get its string representation. Therefore, the output is highly readable and suitable for most scenarios. However, since it uses reflection internally, it is not recommended for heavy use in performance-sensitive scenarios.

bufio ​

bufio provides buffered output methods. It first writes data to memory and outputs to the specified Writer when a certain threshold is reached. The default buffer size is 4KB. It is recommended to use this package for file I/O and network I/O.

go
func main() {
  writer := bufio.NewWriter(os.Stdout)
  defer writer.Flush()
  writer.WriteString("hello world!")
}

You can also combine it with the fmt package:

go
func main() {
  writer := bufio.NewWriter(os.Stdout)
  defer writer.Flush()
  fmt.Fprintln(writer, "hello world!")
}

Formatting ​

The formatted output functionality in Go is basically provided by the fmt.Printf function. If you have learned C-like languages, it will feel very familiar. Here is a simple example:

go
func main() {
  fmt.Printf("hello world, %s!", "jack")
}

Below are all the current format verbs in Go:

#FormatDescriptionAccepted Types
1%%Outputs a percent sign %Any
2%sOutputs string/[] byte valuestring,[] byte
3%qFormats string, output has double quotes "" around the stringstring,[] byte
4%dOutputs decimal integer valueInteger
5%fOutputs floating point numberFloating point
6%eOutputs in scientific notation, can also be used for complex numbersFloating point
7%ESame as %eFloating point
8%gDetermines whether to output %f or %e based on actual situation, removes extra zerosFloating point
9%bOutputs the binary representation of an integerNumeric
10%#bOutputs the full binary representationNumeric
11%oOutputs the octal representation of an integerInteger
12%#oOutputs the full octal representation of an integerInteger
13%xOutputs lowercase hexadecimal representation of an integerNumeric
14%#xOutputs the full lowercase hexadecimal representation of an integerNumeric
15%XOutputs uppercase hexadecimal representation of an integerNumeric
16%#XOutputs the full uppercase hexadecimal representation of an integerNumeric
17%vOutputs the original form of the value, mostly used for data structuresAny
18%+vOutputs struct with field namesAny
19%#vOutputs complete Go syntax format valueAny
20%tOutputs boolean valueBoolean
21%TOutputs the corresponding Go language type valueAny
22%cOutputs the character corresponding to the Unicode code pointint32
23%UOutputs the Unicode code point corresponding to the characterrune,byte
24%pOutputs the address pointed to by the pointerPointer

Use fmt.Sprintf or fmt.Printf to format strings or output formatted strings. Here are some examples:

go
fmt.Printf("%%%s\n", "hello world")

fmt.Printf("%s\n", "hello world")
fmt.Printf("%q\n", "hello world")
fmt.Printf("%d\n", 2<<7-1)

fmt.Printf("%f\n", 1e2)
fmt.Printf("%e\n", 1e2)
fmt.Printf("%E\n", 1e2)
fmt.Printf("%g\n", 1e2)

fmt.Printf("%b\n", 2<<7-1)
fmt.Printf("%#b\n", 2<<7-1)
fmt.Printf("%o\n", 2<<7-1)
fmt.Printf("%#o\n", 2<<7-1)
fmt.Printf("%x\n", 2<<7-1)
fmt.Printf("%#x\n", 2<<7-1)
fmt.Printf("%X\n", 2<<7-1)
fmt.Printf("%#X\n", 2<<7-1)

type person struct {
    name    string
    age     int
    address string
}
fmt.Printf("%v\n", person{"lihua", 22, "beijing"})
fmt.Printf("%+v\n", person{"lihua", 22, "beijing"})
fmt.Printf("%#v\n", person{"lihua", 22, "beijing"})
fmt.Printf("%t\n", true)
fmt.Printf("%T\n", person{})
fmt.Printf("%c%c\n", 20050, 20051)
fmt.Printf("%U\n", '码')
fmt.Printf("%p\n", &person{})

When using other bases, adding a space between % and the format verb can achieve the effect of a separator:

go
func main() {
  str := "abcdefg"
  fmt.Printf("%x\n", str)
  fmt.Printf("% x\n", str)
}

The output of this example is:

61626364656667
61 62 63 64 65 66 67

When using numbers, you can also automatically pad with zeros:

go
fmt.Printf("%09d", 1)
// 000000001

Same for binary:

go
fmt.Printf("%09b", 1<<3)
// 000001000

Error Cases

Number of format specifiers < number of arguments:

go
fmt.Printf("", "") //%!(EXTRA string=)

Number of format specifiers > number of arguments:

go
fmt.Printf("%s%s", "") //%!s(MISSING)

Type mismatch:

go
fmt.Printf("%s", 1) //%!s(int=1)

Missing format verb:

go
fmt.Printf("%", 1) // %!(NOVERB)%!(EXTRA int=1)

Input ​

Common input methods are introduced below:

read ​

You can read input content like reading a file directly:

go
func main() {
  var buf [1024]byte
  n, _ := os.Stdin.Read(buf[:])
  os.Stdout.Write(buf[:n])
}

This is too cumbersome to use and is generally not recommended.

fmt ​

We can use the functions provided by the fmt package, which are similar to C.

go
// Scans text read from os.Stdin, separated by whitespace, newlines are also treated as whitespace
func Scan(a ...any) (n int, err error)

// Similar to Scan, but stops scanning when encountering a newline
func Scanln(a ...any) (n int, err error)

// Scans according to a formatted string
func Scanf(format string, a ...any) (n int, err error)

Read two numbers:

go
func main() {
  var a, b int
  fmt.Scanln(&a, &b)
  fmt.Printf("%d + %d = %d\n", a, b, a+b)
}

Read a fixed-length array:

go
func main() {
  n := 10
  s := make([]int, n)
  for i := range n {
    fmt.Scan(&s[i])
  }
  fmt.Println(s)
}
1 2 3 4 5 6 7 8 9 10
[1 2 3 4 5 6 7 8 9 10]

bufio ​

When there is a large amount of input to read, it is recommended to use bufio.Reader for reading content:

go
func main() {
    reader := bufio.NewReader(os.Stdin)
    var a, b int
    fmt.Fscanln(reader, &a, &b)
    fmt.Printf("%d + %d = %d\n", a, b, a+b)
}

scanner ​

bufio.Scanner is similar to bufio.Reader, but it reads line by line.

go
func main() {
  scanner := bufio.NewScanner(os.Stdin)
  for scanner.Scan() {
    line := scanner.Text()
    if line == "exit" {
      break
    }
    fmt.Println("scan", line)
  }
}

The result is:

first line
scan first line
second line
scan second line
third line
scan third line
exit

TIP

For practicing input and output, you can go to Luogu and solve a few simple ACM-style algorithm problems to get familiar with it.

Complete Example ​

The program below runs as-is: copy it into a file and execute go run main.go, or paste it into the Go Playground.

go
package main

import (
	"bufio"
	"fmt"
	"strings"
)

func main() {
	// Reading formatted values from a stream
	input := strings.NewReader("42 golang\n")
	var n int
	var word string
	fmt.Fscan(input, &n, &word)
	fmt.Printf("%s=%d\n", word, n)

	// Reading line by line
	count := 0
	scanner := bufio.NewScanner(strings.NewReader("line one\nline two\n"))
	for scanner.Scan() {
		count++
		fmt.Println(count, scanner.Text())
	}
}

Expected output:

text
golang=42
1 line one
2 line two

Common Pitfalls ​

  • fmt.Scan splits on whitespace. Use bufio.Scanner when you need whole lines.
  • Scanner lines are copies. scanner.Text() is only valid until the next Scan, so copy it if you keep it.
  • The default Scanner buffer is 64KB. For longer lines, call scanner.Buffer or read directly.
  • fmt.Printf verbs must match types. %d on a string prints %!d(string=...) instead of failing the build.
  • Check the error from Fscan/Scan. Input may end early; unchecked errors hide truncated data. Use bufio.Writer + Flush for many small writes.

Change Log ​

  • 2026-10-14: Added "Before You Start" notes, a complete runnable example with expected output, common pitfalls, and this change log.

Golang by www.golangdev.cn · Adapted in part from Golang 中文学习文档 (MIT, © 寒江蓑笠翁)