[Golang] io パッケージについて
IO すなわち Input と Output だが、このパッケージは OS のプリティティブなシステムコールを抽象化するラッパー。コンピューターの処理は Input 、読み込む reader, コンピューター(OS) からのOutput を書き込む writer のモジュールの二つに処理、もしくは 処理をする Input => Process => Output の構造になっている
まず io パッケージにを説明するためには基本的な io.Writer と io.Reader の理解が必要
そのために Go の hello world コードだがこの fmt.Println を紐解いていく。
package main
import "fmt"
func main() {
msg := "hello world"
fmt.Println(msg)
}
以下、Println の内訳
Fprintln(os.Stdout, a...) のラッパーであることがわかる。
引数は 標準出力と , 受け取った文字列のインターフェース
ちなみに返り値の n は 0
// Println formats using the default formats for its operands and writes to standard output.
// Spaces are always added between operands and a newline is appended.
// It returns the number of bytes written and any write error encountered.
func Println(a ...interface{}) (n int, err error) {
return Fprintln(os.Stdout, a...)
}
次に Fprintln
メモリをアロケート、\n を末尾に挿入、w.Write を実行, メモリを解放 という中身に見える。
// Fprintln formats using the default formats for its operands and writes to w.
// Spaces are always added between operands and a newline is appended.
// It returns the number of bytes written and any write error encountered.
func Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
p := newPrinter()
p.doPrintln(a)
n, err = w.Write(p.buf)
p.free()
return
}
次に w.Write というやつに行きつき、その中の f.write(b) というやつの先に f.pfd.Write(b) という
syscall.Write というやつにたとどりつく、この実態はファイルディスクリプターというやつで
整数値 1 が入っている
こういう経路をだとって標準出力 hello world をえているわけだ。
// Write writes len(b) bytes to the File.
// It returns the number of bytes written and an error, if any.
// Write returns a non-nil error when n != len(b).
func (f *File) Write(b []byte) (n int, err error) {
if err := f.checkValid("write"); err != nil {
return 0, err
}
n, e := f.write(b)
if n < 0 {
n = 0
}
if n != len(b) {
err = io.ErrShortWrite
}
epipecheck(f, e)
if e != nil {
err = f.wrapErr("write", e)
}
return n, err
}
// write writes len(b) bytes to the File.
// It returns the number of bytes written and an error, if any.
func (f *File) write(b []byte) (n int, err error) {
n, err = f.pfd.Write(b)
runtime.KeepAlive(f)
return n, err
}
// Write implements io.Writer.
func (fd *FD) Write(p []byte) (int, error) {
if err := fd.writeLock(); err != nil {
return 0, err
}
defer fd.writeUnlock()
if err := fd.pd.prepareWrite(fd.isFile); err != nil {
return 0, err
}
var nn int
for {
max := len(p)
if fd.IsStream && max-nn > maxRW {
max = nn + maxRW
}
n, err := ignoringEINTRIO(syscall.Write, fd.Sysfd, p[nn:max])
if n > 0 {
nn += n
}
if nn == len(p) {
return nn, err
}
if err == syscall.EAGAIN && fd.pd.pollable() {
if err = fd.pd.waitWrite(fd.isFile); err == nil {
continue
}
}
if err != nil {
return nn, err
}
if n == 0 {
return nn, io.ErrUnexpectedEOF
}
}
}
ここで注目したいのが io.Writer 、これはつまり出力について扱うための抽象化されたインターフェースである。
参考 : ちなみに Go ならわかるシステムプログラミング
osやioとかいっぱいあるけど、それぞれどういう関係なのか解説してくれたもの