1. 程式人生 > >golang 中io包用法(一)

golang 中io包用法(一)

不同的 下一個 同時 顯示 cte () ews 執行 忽略

本文轉自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!
}



golang 中io包用法(一)