io包 copy - golang

 在io包中主要是操作流的一些方法,今天主要學習一下copy。

 在io包(golang 版本 1.12)中,提供了3個公開的copy方法:CopyN(),Copy(),CopyBuffer().

CopyN(dst,src,n) 爲複製src 中 n 個字節到 dst。

Copy(dst,src) 爲複製src 全部到 dst 中。

CopyBuffer(dst,src,buf)爲指定一個buf緩存區,以這個大小完全複製。

 

 他們的關係如下:

  從圖可以看出,無論是哪個copy方法最終都是由copyBuffer()這個私有方法實現的。下面我們看看這個方法的源碼。

func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) {
	// If the reader has a WriteTo method, use it to do the copy.
	// Avoids an allocation and a copy.
	if wt, ok := src.(WriterTo); ok {
		return wt.WriteTo(dst)
	}
	// Similarly, if the writer has a ReadFrom method, use it to do the copy.
	if rt, ok := dst.(ReaderFrom); ok {
		return rt.ReadFrom(src)
	}
	if buf == nil {
		size := 32 * 1024
		if l, ok := src.(*LimitedReader); ok && int64(size) > l.N {
			if l.N < 1 {
				size = 1
			} else {
				size = int(l.N)
			}
		}
		buf = make([]byte, size)
	}
	for {
		nr, er := src.Read(buf)
		if nr > 0 {
			nw, ew := dst.Write(buf[0:nr])
			if nw > 0 {
				written += int64(nw)
			}
			if ew != nil {
				err = ew
				break
			}
			if nr != nw {
				err = ErrShortWrite
				break
			}
		}
		if er != nil {
			if er != EOF {
				err = er
			}
			break
		}
	}
	return written, err
}

 從這部分代碼可以看出,複製主要分爲3種。

 1.如果被複制的Reader(src)會嘗試能否斷言成writerTo,如果可以則直接調用下面的writerTo方法

 2.如果 Writer(dst) 會嘗試能否斷言成ReadFrom ,如果可以則直接調用下面的readfrom方法

 3.如果都木有實現,則調用底層read實現複製。

 

其中,有這麼一段代碼:

if buf == nil {
		size := 32 * 1024
		if l, ok := src.(*LimitedReader); ok && int64(size) > l.N {
			if l.N < 1 {
				size = 1
			} else {
				size = int(l.N)
			}
		}
		buf = make([]byte, size)
	}

這部分主要是實現了對Copy和CopyN的處理。通過上面的調用關係圖,我們看出CopyN在調用後,會把Reader轉成LimiteReader。

區別是如果Copy,直接建立一個緩存區默認大小爲 32* 1024 的buf,如果是CopyN 會先判斷 要複製的字節數 如果小於默認大小,會創建一個等於要複製字節數的buf。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章