본문으로 바로가기

[Golang] 표준 입출력

category Programming/Go 2022. 10. 23. 22:48

OS가 제공하는 표준 입출력 스트림을(standard input/output) 사용하여 입력과 출력을 간편하게 처리할 수 있다.

Go에서는 Go 언어 기본 패키지는 fmt에서 표준 입출력 기능을 제공한다.

  • fmt패키지는 3가지 표준 출력용 함수를 제공한다.
    Print()  함수 입력값들을 출력한다.
    PrintIn() 함수 입력값들을 출력 및 개행한다.
    Printf() 서식(format)에 맞도록 입력값들을 출력한다.

서식문자

Printf() 함수는 다음과 같은 형식으로 사용된다.

Printf(서식 지정자, 인수1, 인수2)
  • 서식 지정자 설명
    구분 설명
    %v 데이터 타입에 맞춰서 기본 형태로 출력한다.
    %T 데이터 타입 출력한다.
    %t 불리언을 true/false로 출력
    %d 10진수 정숫값으로 출력 (only 정수타입)
    %b 2진수로 출력
    %c 유니코드 문자를 출력
    %o 8진수로 출력
    %O 앞에 8진수임을 표시하는 0o를 붙여서 8진수로 값을 출력
    %x 16진수로 값을 출력 (10 이상 값을 a-f 소문자로 표시)
    %X 16진수로 값을 출력 (10 이상 값을 a-f 대문자로 표시)
    %e %E 지수 형태로 실숫값을 출력 (실수 타입만 가능)
    %f %F 지수 형태가 아닌 실숫값 그대로 출력 (실수 타입만 가능)
    %g %G 값이 큰 실숫값은 지수 형태(%e)로 출력
    %s 문자열을 출력
    %q 특수문자 기능을 동작하지 않고 그대로 출력
    %p 메모리 주솟값을 출력

최소 출력 너비 지정

서식 문자를 이용하여 다음과 같은 작업을 할 수 있다.

  • 최소 출력 너비 지정
  • 공란 채우기
  • 왼쪽 정렬하기

1️⃣ 최소 출력 너비 지정

package main

import "fmt"

func main() {
	var a = 123
	var b = 456

	fmt.Printf("%5d, %5d\\n", a, b)
}

>   123,   456

%와 타입을 나타내는 문자 사이에 숫자를 넣어서 너비를 지정할 수 있다.

  • %5d는 최소 5칸을 사용하여 정숫값을 출력한다.

2️⃣ 공란 채우기

package main

import "fmt"

func main() {
	var a = 123
	var b = 456

	fmt.Printf("%05d, %05d\\n", a, b)
}
>00123, 00456

너비 앞에 0을 붙이면 빈자리를 0으로 채운다.

  • 최소 5칸을 사용하고 공란에 0을 채운다.

3️⃣ 왼쪽 정렬하기

package main

import "fmt"

func main() {
	var a = 123
	var b = 456

	fmt.Printf("%-5d, %-05d\\n", a, b)
}
>123  , 456

마이너스를 붙이면 왼쪽을 기준선 삼아 출력한다.

  • 일정 간격으로 숫자들을 출력할 수 있다.

실수 소수점 이하 자릿수

실숫값에는 소수점 이하 자릿수도 지정할 수 있다.

  • %f
    • 실수를 출력한다.
    • ex) %5.2f : 최소 너비 5칸에 소수점 이하 값 2개를 출력한다.
  • %g
    • 실수를 정수부와 소수점 이하 숫자를 포함하여 출력 숫자를 제한한다.
    • ex) %5.3g : 최소 너비 5칸에 소수점 이하 포함하여 총 숫자 3개로 표현한다.

특수문자

\n 줄바꿈 한다.
\t 탭을 삽입한다.
\\ \ 자체를 출력한다.
\” “를 출력한다.
큰따옴표로 묶인 문자열 내부에 따옴표를 넣을 때 사용한다.

표준입력

표준 입출력 장치에서 데이터를 얻어온다.

  • 일반적으로는 키보드가 표준 입력 장치이다.
  • 아래의 함수는 변수들의 메모리 주소(&)를 인수로 넘겨줘야 한다.
Scan() 값을 채워넣을 변수들의 메모리 주소를 인수로 받는다.
Scanf() 표준 입력에서 서식형태로 값을 입력받는다.
Scanln() 표준 입력에서 한 줄을 읽어서 인수로 들어온 변수 메모리 주소에 값을 채워준다.

예제

Scan()

Scan()함수는 값을 채워넣을 변수들의 메모리 주소를 인수로 받는다.

  • 한 번에 여러 값을 입력받을 떄는 변수 사이를 공란을 두어 구분한다.
package main

import "fmt"

func main() {
	var a int // ❶ 값을 저장할 변수
	var b int

	n, err := fmt.Scan(&a, &b) // ❷ 입력 두 개 받기
	if err != nil {            // ❸ 에러가 발생하면 에러 코드 출력
		fmt.Println(n, err)
	} else { // ➍ 정상 입력되면 입력값 출력
		fmt.Println(n, a, b)
	}
}
  • Scan() 함수의 입력으로 쓸 때에는 변수 앞에 &를 붙여서 변수의 메모리 주소를 입력으로 넘겨야한다.
  • err가 nil이 아니면 에러이다.

Scanf()

Scanf()는 서식에 맞춘 입력을 받는다.

💡 서식에 맞춰서 입력하기가 힘들기 때문에 Scan()이나 Scanln() 함수 사용을 추천한다.
//ch5/ex5.6/ex5.6.go
package main

import "fmt"

func main() {
	var a int
	var b int

	n, err := fmt.Scanf("%d %d\\n", &a, &b) // ❶ 입력 두 개 받기
	if err != nil {
		fmt.Println(n, err)
	} else {
		fmt.Println(n, a, b)
	}
}

Scanln()

한 줄을 입력받아서 인수로 들어온 변수 메모리 주소에 값을 채워준다.

  • Scan()과 다른점은 마지막 입력값 이후 반드시 enter 키로 입력을 종료해야 한다.
//ch5/ex5.7/ex5.7.go
package main

import "fmt"

func main() {
	var a int
	var b int

	n, err := fmt.Scanln(&a, &b) // ❶ 값을 입력받습니다.
	if err != nil {              // 에러 발생 시
		fmt.Println(err) // 에러를 출력합니다.
	} else {
		fmt.Println(n, a, b)
	}
}

Scan() 함수의 동작원리

만약, int 타입 입력을 받고자 사용자가 “Hello 4” 를 입력한다면 가장 먼저 입력된 데이터부터 읽어오기 때문에(FIFO 방식) 데이터가 거꾸로 저장된다.

  1. Scan()함수는 가장 먼저 입력된 글자가 읽히기 떄문에 H를 읽어온다.
    • 한 번 읽은 데이터는 다시 읽어올 수 없다.
  2. 그런 다음 읽어온 글자가 원하는 타입인지 판단한다.
    • 위 경우에는 int 타입에 string이라 Error를 반환한다.
  3. 그 후에 다시 Scanln()이 호출됐을 때 새로운 입력을 받는게 아니라 기존에 남아있는 표준 입력 스트림에서 다시 값을 가져오기 때문에 ‘e’를 가져오고 Error를 반환한다.

따라서 여러번 Scan() 함수를 호출할 때 위와 같은 문제에서 벗어나려면 입력에 실패한 경우 표준 입력 스트림을 지워줘야 한다.

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	stdin := bufio.NewReader(os.Stdin) // 표준 입력을 읽는 객체

	var a int
	var b int

	n, err := fmt.Scanln(&a, &b)
	if err != nil { // 에러 발생 시
		fmt.Println(err) // 에러 출력
		stdin.ReadString('\\n') // 표준 입력 스트림 지우기
	} else {
		fmt.Println(n, a, b)
	}

	n, err = fmt.Scanln(&a, &b) // 다시 입력받기
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println(n, a, b)
	}
}
  • bufio
    • 표준 입력 스트림에서 한 줄을 읽어오는 데 bufio, os 등의 패키지를 사용한다.
    • bufio는 입력 스트림으로부터 한 줄을 읽는 Reader 객체를 제공한다.
  • stdin := bufio.NewReader(os.Stdin)
    • NewReader() 함수는 인수로 입력되는 입력 스트림을 가지고 Reader 객체를 생성해준다.
    • 여기서는 표준 입력 스트림을 나타내는 os.Stdin을 사용하여 Reader 객체를 만든다.
  • stdin.ReadString('\\n')
    • 줄바꿈 문자가 나올 때 까지 읽는다.
    • 이렇게 하면 표준 입력 스트림이 비워진다.

'Programming > Go' 카테고리의 다른 글

[Golang] 함수 (Function)  (1) 2022.10.29
[Golang] 연산자 (Operator)  (0) 2022.10.29
[Golang] 변수  (0) 2022.10.22
[Golang] 코드 실행과정  (0) 2022.10.17
[Golang] Go는 어떤 언어?  (1) 2022.09.23