本文轉自Golove博客:http://www.cnblogs.com/golove/p/3276678.html
io 包為I/O原語提供了基礎的接口.它主要包裝了這些原語的已有實現,如 os 包中的那些,抽象成函數性的共享公共接口,加上一些其它相關的原語。
由於這些接口和原語以不同的實現包裝了低級操作,因此除非另行通知,否則客戶不應假定它們對於並行執行是安全的。
在io包中最重要的是兩個接口:Reader和Writer接口,首先來介紹這兩個接口.
type Reader interface { Read(p []byte) (n int, err error) }
Reader 接口包裝了基本的 Read 方法。
Read 將 len(p) 個字節讀取到 p 中。它返回讀取的字節數 n(0 <= n <= len(p))以及任何遇到的錯誤。即使 Read 返回的 n < len(p),它也會在調用過程中使用 p的全部作為暫存空間。若一些數據可用但不到 len(p) 個字節,Read 會照例返回可用的東西,而不是等待更多。
當 Read 在成功讀取 n > 0 個字節后遇到一個錯誤或 EOF 情況,它就會返回讀取的字節數。它會從相同的調用中返回(非nil的)錯誤或從隨后的調用中返回錯誤(和 n == 0)。這種一般情況的一個例子就是 Reader 在輸入流結束時會返回一個非零的字節數,可能的返回不是 err == EOF 就是 err == nil。無論如何,下一個 Read 都應當返回 0, EOF。
調用者應當總在考慮到錯誤 err 前處理 n > 0 的字節。這樣做可以在讀取一些字節,以及允許的 EOF 行為后正確地處理I/O錯誤。
Read 的實現會阻止返回零字節的計數和一個 nil 錯誤,調用者應將這種情況視作空操作。
type Writer interface { Write(p []byte) (n int, err error) }
Writer 接口包裝了基本的 Write 方法。
Write 將 len(p) 個字節從 p 中寫入到基本數據流中。它返回從 p 中被寫入的字節數n(0 <= n <= len(p))以及任何遇到的引起寫入提前停止的錯誤。若 Write 返回的n < len(p),它就必須返回一個非nil的錯誤。Write 不能修改此切片的數據,即便它是臨時的。
Io包中的函數(方法):
func ReadFull(r Reader, buf []byte) (n int, err error)
這個函數可以把對象 r 中的數據讀出來,然后存入一個緩沖區 buf 中,以便其它代碼可以處理 buf 中的數據。
這里有個問題,ReadFull 函數究竟可以讀取哪些對象的數據?可以讀文件中的數據嗎?可以讀網絡中的數據嗎?可以讀數據庫中的數據嗎?可以讀磁盤中的扇區嗎?可以讀內存中的數據嗎?
答案是 ReadFull 可以讀取任何對象的數據,但是有個前提,就是這個對象必須符合 Reader 的標准。
Reader 的標准是什么呢?下面是 Reader 的定義:
type Reader interface { Read(p []byte) (n int, err error) }
從上面的定義可以看出,Reader 的標准很簡單,只要某個對象實現了 Read 方法,這個對象就符合了 Reader 的標准,就可以被 ReadFull 讀取。
太簡單了,只需要實現 Read 方法,不需要做其它任何事情。下面我們就來定義一個自己的類型,然后實現 Read 方法:
// 定義一個 Ustr 類型(以 string 為基類型) type Ustr string // 實現 Ustr 類型的 Read 方法 func (s Ustr) Read(p []byte) (n int, err error) { i, ls, lp := 0, len(s), len(p) for ; i < ls && i < lp; i++ { // 將小寫字母轉換為大寫字母,然后寫入 p 中 if s[i] >= 'a' && s[i] <= 'z' { p[i] = s[i] + 'A' - 'a' } else { p[i] = s[i] } } // 根據讀取的字節數設置返回值 switch i { case lp: return i, nil case ls: return i, io.EOF default: return i, errors.New("Read Fail") } }
接下來,我們就可以用 ReadFull 方法讀取 Ustr 對象的數據了:
func main() { us := Ustr("Hello World!") // 創建 Ustr 對象 us buf := make([]byte, 32) // 創建緩沖區 buf n, err := io.ReadFull(us, buf) // 將 us 中的數據讀取到 buf 中 fmt.Printf("%s\n", buf) // 顯示 buf 中的內容 // HELLO WORLD! fmt.Println(n, err) // 顯示返回值 // 12 unexpected EOF }
我們很快就實現了 Reader 的要求,這個 Reader 就是一個接口,接口就是一個標准,一個要求,一個規定,這個規定就是“要實現接口中的方法”。只要某個對象符合 Reader 接口的要求,那么這個對象就可以當作 Reader 接口來使用,就可以傳遞給 ReadFull 方法。
所以,只要文件對象實現了 Read 方法,那么 ReadFull 就可以讀取文件中的數據,只要網絡對象實現了 Read 方法,ReadFull 就可以讀取網絡中的數據,只要數據庫實現了 Read 方法,ReadFull 就可以讀取數據庫中的數據,只要磁盤對象實現了 Read 方法,ReadFull 就可以讀磁盤中的數據,只要內存對象實現了 Read 方法,ReadFull 就可以讀取內存中的數據,只要任何一個對象實現了 Read 方法,ReadFull 就可以讀取該對象的數據。
在 io 包中,定義了許多基本的接口類型,Go 語言的標准庫中大量使用了這些接口(就像 ReadFull 一樣使用它們),下面我們就來看一看都有哪些接口:
// Writer 接口封裝了基本的 Write 方法 // Write 方法用於將 p 中的數據寫入到對象的數據流中 // 返回寫入的字節數 n (0 <= n <= len(p)) 和寫入時遇到的任何錯誤 // 如果 p 中的數據全部被寫入,則 err 應該返回 nil // 如果 p 中的數據無法被全部寫入,則 err 應該返回相應的錯誤信息 // Writer 用來存入數據 type Writer interface { Write(p []byte) (n int, err error) } ------------------------------------------------------------ // Closer 接口封裝了基本的 Close 方法 // Close 一般用於關閉文件,關閉連接,關閉數據庫等 // Close 用來關閉數據 type Closer interface { Close() error } ------------------------------------------------------------ // Seeker 接口封裝了基本的 Seek 方法 // Seek 設置下一次讀寫操作的指針位置,每次的讀寫操作都是從指針位置開始的 // whence 的含義: // 如果 whence 為 0:表示從數據的開頭開始移動指針 // 如果 whence 為 1:表示從數據的當前指針位置開始移動指針 // 如果 whence 為 2:表示從數據的尾部開始移動指針 // offset 是指針移動的偏移量 // 返回移動后的指針位置和移動過程中遇到的任何錯誤 // Seeker 用來移動數據的讀寫指針 type Seeker interface { Seek(offset int64, whence int) (ret int64, err error) } ------------------------------------------------------------ // 下面是這些接口的組合接口 type ReadWriter interface { Reader Writer } type ReadSeeker interface { Reader Seeker } type WriteSeeker interface { Writer Seeker } type ReadWriteSeeker interface { Reader Writer Seeker } type ReadCloser interface { Reader Closer } type WriteCloser interface { Writer Closer } type ReadWriteCloser interface { Reader Writer Closer } ------------------------------------------------------------ // ReaderFrom 接口封裝了基本的 ReadFrom 方法 // ReadFrom 從 r 中讀取數據到對象的數據流中 // 直到 r 返回 EOF 或 r 出現讀取錯誤為止 // 返回值 n 是讀取的字節數 // 返回值 err 就是 r 的返回值 err // ReadFrom 用來讀出 r 中的數據 type ReaderFrom interface { ReadFrom(r Reader) (n int64, err error) } ------------------------------------------------------------ // WriterTo 接口封裝了基本的 WriteTo 方法 // WriterTo 將對象的數據流寫入到 w 中 // 直到對象的數據流全部寫入完畢或遇到寫入錯誤為止 // 返回值 n 是寫入的字節數 // 返回值 err 就是 w 的返回值 err // WriteTo 用來將數據寫入 w 中 type WriterTo interface { WriteTo(w Writer) (n int64, err error) } ------------------------------------------------------------ // ReaderAt 接口封裝了基本的 ReadAt 方法 // ReadAt 從對象數據流的 off 處讀出數據到 p 中 // 忽略數據的讀寫指針,從數據的起始位置偏移 off 處開始讀取 // 如果對象的數據流只有部分可用,不足以填滿 p // 則 ReadAt 將等待所有數據可用之后,繼續向 p 中寫入 // 直到將 p 填滿后再返回 // 在這點上 ReadAt 要比 Read 更嚴格 // 返回讀取的字節數 n 和讀取時遇到的錯誤 // 如果 n < len(p),則需要返回一個 err 值來說明 // 為什么沒有將 p 填滿(比如 EOF) // 如果 n = len(p),而且對象的數據沒有全部讀完,則 // err 將返回 nil // 如果 n = len(p),而且對象的數據剛好全部讀完,則 // err 將返回 EOF 或者 nil(不確定) type ReaderAt interface { ReadAt(p []byte, off int64) (n int, err error) } ------------------------------------------------------------ // WriterAt 接口封裝了基本的 WriteAt 方法 // WriteAt 將 p 中的數據寫入到對象數據流的 off 處 // 忽略數據的讀寫指針,從數據的起始位置偏移 off 處開始寫入 // 返回寫入的字節數和寫入時遇到的錯誤 // 如果 n < len(p),則必須返回一個 err 值來說明 // 為什么沒有將 p 完全寫入 type WriterAt interface { WriteAt(p []byte, off int64) (n int, err error) } ------------------------------------------------------------ // ByteReader 接口封裝了基本的 ReadByte 方法 // ReadByte 從對象的數據流中讀取一個字節到 c 中 // 如果對象的數據流中沒有可讀數據,則返回一個錯誤信息 type ByteReader interface { ReadByte() (c byte, err error) } ------------------------------------------------------------ // ByteScanner 在 ByteReader 的基礎上增加了一個 UnreadByte 方法 // UnreadByte 用於撤消最后一次的 ReadByte 操作 // 即將對象的讀寫指針移到上次 ReadByte 之前的位置 // 如果上一次的操作不是 ReadByte,則 UnreadByte 返回一個錯誤信息 type ByteScanner interface { ByteReader UnreadByte() error } ------------------------------------------------------------ // ByteWriter 接口封裝了基本的 WriteByte 方法 // WriteByte 將一個字節 c 寫入到對象的數據流中 // 返回寫入過程中遇到的任何錯誤 type ByteWriter interface { WriteByte(c byte) error } ------------------------------------------------------------ // RuneReader 接口封裝了基本的 ReadRune 方法 // ReadRune 從對象的數據流中讀取一個字符到 r 中 // 如果對象的數據流中沒有可讀數據,則返回一個錯誤信息 type RuneReader interface { ReadRune() (r rune, size int, err error) } ------------------------------------------------------------ // RuneScanner 在 RuneReader 的基礎上增加了一個 UnreadRune 方法 // UnreadRune 用於撤消最后一次的 ReadRune 操作 // 即將對象的讀寫指針移到上次 ReadRune 之前的位置 // 如果上一次的操作不是 ReadRune,則 UnreadRune 返回一個錯誤信息 type RuneScanner interface { RuneReader UnreadRune() error } ------------------------------------------------------------ // bytes.NewBuffer 實現了很多基本的接口,可以通過 bytes 包學習接口的實現 func main() { bb := bytes.NewBuffer([]byte("Hello World!")) b := make([]byte, 32) bb.Read(b) fmt.Printf("%s\n", b) // Hello World! bb.WriteString("New Data!\n") bb.WriteTo(os.Stdout) // New Data! bb.WriteString("Third Data!") bb.ReadByte() fmt.Println(bb.String()) // hird Data! bb.UnreadByte() fmt.Println(bb.String()) // Third Data! } ------------------------------------------------------------ // 下面是 io 包中的函數 ------------------------------------------------------------ // WriteString 將字符串 s 寫入到 w 中 // 返回寫入的字節數和寫入過程中遇到的任何錯誤 // 如果 w 實現了 WriteString 方法 // 則調用 w 的 WriteString 方法將 s 寫入 w 中 // 否則,將 s 轉換為 []byte // 然后調用 w.Write 方法將數據寫入 w 中 func WriteString(w Writer, s string) (n int, err error) func main() { // os.Stdout 實現了 Writer 接口 io.WriteString(os.Stdout, "Hello World!") // Hello World! } ------------------------------------------------------------ // ReadAtLeast 從 r 中讀取數據到 buf 中,要求至少讀取 min 個字節 // 返回讀取的字節數 n 和讀取過程中遇到的任何錯誤 // 如果 n < min,則 err 返回 ErrUnexpectedEOF // 如果 r 中無可讀數據,則 err 返回 EOF // 如果 min 大於 len(buf),則 err 返回 ErrShortBuffer // 只有當 n >= min 時 err 才返回 nil func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error) func main() { r := strings.NewReader("Hello World!") b := make([]byte, 32) n, err := io.ReadAtLeast(r, b, 20) fmt.Printf("%s\n%d, %v", b, n, err) // Hello World! // 12, unexpected EOF } ------------------------------------------------------------ // ReadFull 的功能和 ReadAtLeast 一樣,只不過 min = len(buf),其中要求最少讀取的字節數目是len(buf),當r中數據少於len(buf)時便會報錯 func ReadFull(r Reader, buf []byte) (n int, err error) func main() { r := strings.NewReader("Hello World!") b := make([]byte, 32) n, err := io.ReadFull(r, b) fmt.Printf("%s\n%d, %v", b, n, err) // Hello World! // 12, unexpected EOF } ------------------------------------------------------------ // CopyN 從 src 中復制 n 個字節的數據到 dst 中 // 它返回復制的字節數 written 和復制過程中遇到的任何錯誤 // 只有當 written = n 時,err 才返回 nil // 如果 dst 實現了 ReadFrom 方法,則調用 ReadFrom 來執行復制操作 func CopyN(dst Writer, src Reader, n int64) (written int64, err error) func main() { r := strings.NewReader("Hello World!") n, err := io.CopyN(os.Stdout, r, 20) fmt.Printf("\n%d, %v", n, err) // Hello World! // 12, EOF } ------------------------------------------------------------ // Copy 從 src 中復制數據到 dst 中,直到所有數據復制完畢 // 返回復制過程中遇到的任何錯誤 // 如果數據復制完畢,則 err 返回 nil,而不是 EOF // 如果 dst 實現了 ReadeFrom 方法,則調用 dst.ReadeFrom(src) 復制數據 // 如果 src 實現了 WriteTo 方法,則調用 src.WriteTo(dst) 復制數據 func Copy(dst Writer, src Reader) (written int64, err error) func main() { r := strings.NewReader("Hello World!") n, err := io.Copy(os.Stdout, r) fmt.Printf("\n%d, %v", n, err) // Hello World! // 12, <nil> } ------------------------------------------------------------ // LimitReader 覆蓋了 r 的 Read 方法 // 使 r 只能讀取 n 個字節的數據,讀取完畢后返回 EOF func LimitReader(r Reader, n int64) Reader // LimitedReader 結構用來實現 LimitReader 的功能 type LimitedReader struct func main() { r := strings.NewReader("Hello World!") lr := io.LimitReader(r, 5) n, err := io.CopyN(os.Stdout, lr, 20) fmt.Printf("\n%d, %v", n, err) // Hello // 5, EOF } ------------------------------------------------------------ // NewSectionReader 封裝 r,並返回 SectionReader 類型的對象 // 使 r 只能從 off 的位置讀取 n 個字節的數據,讀取完畢后返回 EOF func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader // SectionReader 結構用來實現 NewSectionReader 的功能 // SectionReader 實現了 Read、Seek、ReadAt、Size 方法 type SectionReader struct // Size 返回 s 中被限制讀取的字節數 func (s *SectionReader) Size() func main() { r := strings.NewReader("Hello World!") sr := io.NewSectionReader(r, 0, 5) n, err := io.CopyN(os.Stdout, sr, 20) fmt.Printf("\n%d, %v", n, err) fmt.Printf("\n%d", sr.Size()) // World // 5, EOF // 5 } ------------------------------------------------------------ // TeeReader 覆蓋了 r 的 Read 方法 // 使 r 在讀取數據的同時,自動向 w 中寫入數據 // 所有寫入時遇到的錯誤都被作為 err 返回值 func TeeReader(r Reader, w Writer) Reader func main() { r := strings.NewReader("Hello World!") tr := io.TeeReader(r, os.Stdout) b := make([]byte, 32) tr.Read(b) // World World! }