入出力 #
標準入力から読み込む #
標準入力は os パッケージの変数 os.Stdin
である。
これは os.File
型の値であるので、下記のファイル読み込み処理が使える。
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
if err := scanner.Err(); err != nil {
panic(err)
}
}
標準出力に書き込む #
標準出力は os パッケージの変数 os.Stdout
である。
これは os.File
型の値であるので、下記のファイル書き込み処理が使える。
package main
import (
"fmt"
"os"
)
func main() {
// 文字列を書き込み
size, err := os.Stdout.WriteString("Hello World\n")
fmt.Println(size, err) // == 12 <nil>
// フォーマット指定で書き込み
fmt.Fprintf(os.Stdout, "The number is %d\n", 42)
}
エラー出力に書き込む #
エラー出力は os パッケージの変数 os.Stderr
である。
これは os.File
型の値であるので、下記のファイル書き込み処理が使える。
package main
import (
"fmt"
"os"
)
func main() {
// 文字列を書き込み
size, err := os.Stderr.WriteString("Hello World\n")
fmt.Println(size, err) // == 12 <nil>
// フォーマット指定で書き込み
fmt.Fprintf(os.Stderr, "The number is %d\n", 42)
}
コマンドライン引数を取得する #
コマンドライン引数は os パッケージの変数 os.Args
に入る。
これは単なる []string
であり、0 番目の要素が実行ファイル名、それ以降が引数となる。
package main
import (
"fmt"
"os"
)
func main() {
fmt.Printf("%#v", os.Args)
}
/* 実行コマンドと実行結果
$ go run main.go 1 2 3
[]string{"/var/folders/wm/qmc3zr9n11x5yp1rgqx7rsp40000gp/T/go-build1344239269/b001/exe/main", "1", "2", "3"}
$ go run main.go -a 1 -b 2 -c 3
[]string{"/var/folders/wm/qmc3zr9n11x5yp1rgqx7rsp40000gp/T/go-build1270504581/b001/exe/main", "-a", "1", "-b", "2", "-c", "3"}
*/
参考ドキュメント: os
コマンドラインオプションを取得する #
flag
パッケージを使ってコマンドラインオプションを取得する。
flag
を使うとコマンドライン引数とコマンドラインオプションを区別して取得できる。
オプションは変数として flag.Bool
などの専用関数で定義しておき、実行時にパースする。
オプション同士の順番の前後は定義順とは関係ないが、引数はオプションの後に指定する必要がある。
package main
import (
"flag"
"fmt"
)
// オプションの定義
// オプションを受ける変数とオプション名、デフォルト値、説明を定義する
var b = flag.Bool("b", false, "bool option usage")
var s = flag.String("str", "default value", "string option usage")
var i = flag.Int("i", 10, "int option test")
var f = flag.Float64("f", .1, "float option usage")
func main() {
// オプションをパースする
flag.Parse()
// オプションの値を表示
fmt.Printf("b: %#v\n", *b)
fmt.Printf("s: %#v\n", *s)
fmt.Printf("i: %#v\n", *i)
fmt.Printf("f: %#v\n", *f)
// 引数を表示
fmt.Printf("args: %#v\n", flag.Args())
}
/* 実行コマンドと実行結果
$ go run main.go
b: false
s: "default value"
i: 10
f: 0.1
args: []string{}
$ go run main.go -str hello -b -i 100 -f 2.2 foo bar baz
b: true
s: "hello"
i: 100
f: 2.2
args: []string{"foo", "bar", "baz"}
*/
参考ドキュメント: flag
データを出力するものを io.Reader として抽象化する #
Go 言語ではデータを出力するものはio.Reader
インターフェイスとして抽象化される。
io.Reader
を実装するものは例えば、ファイルハンドルや HTTP のレスポンスやデータ変換処理結果など様々である。
これら様々なものが io.Reader
として抽象化されることで、データ読み込み処理が再利用しやすく便利になる。
io.Reader
は Read
メソッドのみを要求する単純なインターフェイスである。
type Reader interface {
Read(p []byte) (n int, err error)
}
以下の例では io.Reader
の代表的な実装である os.File
を io.Reader
として扱いデータを読み込んでみる。
package main
import (
"bytes"
"fmt"
"io"
"os"
)
func main() {
// ファイルの作成
err := os.WriteFile("file.txt", []byte("Hello World"), 0666)
if err != nil {
panic(err)
}
// os.File の取得
f, err := os.Open("file.txt")
if err != nil {
panic(err)
}
// ファイルを io.Reader としてデータの読み込み
data := read(f)
fmt.Println(string(data)) // == Hello World
}
func read(r io.Reader) []byte {
buf := bytes.Buffer{}
b := make([]byte, 10)
for {
n, err := r.Read(b)
if err == io.EOF {
break
}
buf.Write(b[:n])
}
return buf.Bytes()
}
io.Reader からデータを読み込む #
io.Reader
から行ごとにデータを読み込む方法と、一定のサイズごとに読み込む方法は下記を参照のこと。
ファイルハンドルである os.File
は io.Reader
を実装するので、ファイルからデータを読む方法はそのまま io.Reader
でも利用できる場合が多い。
io.Reader
から全てのデータを一度の読み込む方法はこちら。
package main
import (
"fmt"
"io"
"strings"
)
func main() {
// 文字列から io.Reader を実装する strings.Reader を作成する
r := strings.NewReader("hello world")
// データを読み込む
data, err := io.ReadAll(r)
fmt.Println(string(data), err) // == hello world <nil>
}
参考ドキュメント: bytes , io , strings
io.Reader のデータを加工して返すフィルタリング関数を作成する #
io.Reader
のデータに一定間隔ごとに改行を挿入する関数を作成する
package main
import (
"bytes"
"fmt"
"io"
"strings"
)
func main() {
r := strings.NewReader("hello world")
data, err := io.ReadAll(newLineInjector(r, 3))
fmt.Println(string(data), err)
/* 出力
hel
lo
wor
ld
<nil>
*/
r.Reset("hello world")
data, err = io.ReadAll(newLineInjector(r, 5))
fmt.Println(string(data), err)
/* 出力
hello
worl
d
<nil>
*/
}
func newLineInjector(r io.Reader, size int) io.Reader {
buf := new(bytes.Buffer)
b := make([]byte, size)
for {
n, err := r.Read(b)
if err == io.EOF {
break
}
if err != nil {
panic(err)
}
buf.Write(b[:n])
buf.Write([]byte{'\n'})
}
return buf
}
参考ドキュメント: bytes , io , strings
データを入力するものを io.Writer として抽象化する #
Go 言語ではデータを入力するものはio.Writer
インターフェイスとして抽象化される。
io.Writer
を実装するものは例えば、ファイルハンドルや標準出力やデータ変換処理への入力など様々である。
これら様々なものが io.Writer
として抽象化されることで、データ書き込み処理が再利用しやすく便利になる。
io.Write
は Write
メソッドのみを要求する単純なインターフェイスである。
type Writer interface {
Write(p []byte) (n int, err error)
}
以下の例では io.Writer
の代表的な実装である os.File
を io.Write
として扱いデータを書き込んでみる。
package main
import (
"fmt"
"io"
"os"
)
func main() {
// ファイルの作成
f, err := os.OpenFile("file.txt", os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
panic(err)
}
// ファイルへ書き込む
if err := write(f); err != nil {
panic(err)
}
// 書き込みの確認
data, err := os.ReadFile("file.txt")
fmt.Println(string(data), err) // == Hello World <nil>
}
func write(w io.Writer) error {
_, err := w.Write([]byte("Hello World"))
return err
}