最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文詳解golang通過(guò)io包進(jìn)行文件讀寫(xiě)

 更新時(shí)間:2023年04月26日 08:40:16   作者:進(jìn)擊的davis  
這篇文章主要介紹了golang通過(guò)io包進(jìn)行文件讀寫(xiě)文中有詳細(xì)的代碼示例。對(duì)學(xué)習(xí)或工資有很好的幫助,需要的小伙伴可以參考閱讀一下

在 golang 語(yǔ)言中,實(shí)現(xiàn)io的讀與寫(xiě),只要實(shí)現(xiàn)了如下的讀寫(xiě)接口即可:

// go 1.19/src/io/io.go

type Reader interface {
	Read(p []byte) (n int, err error)
}

type Writer interface {
	Write(p []byte) (n int, err error)
}

golang 語(yǔ)言自身提供了很多實(shí)現(xiàn)這兩個(gè)接口的結(jié)構(gòu)體,比較典型的有:io、os、bytes.buffer、strings、bufio等,這些解決了文件的讀寫(xiě),字節(jié)、字符串的讀寫(xiě),或者是帶緩沖的讀寫(xiě)等。

今天我們先來(lái)看看 io包 中提供的這些接口,簡(jiǎn)單了解下相關(guān)原理。

1.io包的讀寫(xiě)函數(shù)

典型的相關(guān)函數(shù)聲明如下:

// 讀操作
func ReadAll(r Reader) ([]byte, error) {...}

// 寫(xiě)操作
func Copy(dst Writer, src Reader) (written int64, err error) {...}


func WriteString(w Writer, s string) (n int, err error) {...}

在上面的 ReadAll() 函數(shù)中,接收一個(gè) Reader 類(lèi)型的參數(shù),比如 os.File 類(lèi)型,又或者是其他的實(shí)現(xiàn)了 io.Reader 接口的結(jié)構(gòu)體類(lèi)型,輸出讀取到的內(nèi)容,以字節(jié)數(shù)組形式輸出,外附一個(gè) error 錯(cuò)誤,我們進(jìn)一步看看其內(nèi)部實(shí)現(xiàn):

func ReadAll(r Reader) ([]byte, error) {
        // 新建字節(jié)數(shù)組,cap=512
	b := make([]byte, 0, 512)
        // 開(kāi)啟循環(huán)讀取內(nèi)容
	for {
                // 
		if len(b) == cap(b) {
			// Add more capacity (let append pick how much).
			b = append(b, 0)[:len(b)]
		}
                // 讀取 reader中的內(nèi)容,填充到對(duì)應(yīng)部分
		n, err := r.Read(b[len(b):cap(b)])
		b = b[:len(b)+n]
                // 如果讀到了結(jié)尾,可以返回?cái)?shù)據(jù)
		if err != nil {
			if err == EOF {
				err = nil
			}
			return b, err
		}
	}
}

從上面源碼可以知道,io.ReadAll() 函數(shù),通過(guò)一次讀取 Reader 中的所有內(nèi)容,如果是小文件無(wú)所謂,占用內(nèi)存有限,但如果是好幾個(gè)G的文件呢,是不是,本來(lái)服務(wù)器內(nèi)存有限,以下占用幾G內(nèi)存,這樣讀取不太合理,當(dāng)然,golang 也為我們提供了帶緩沖的讀取,這是后話,后面再討論。

接下來(lái)看看寫(xiě)入操作的源碼實(shí)現(xiàn):

// io.Copy()
func Copy(dst Writer, src Reader) (written int64, err error) {
	return copyBuffer(dst, src, nil) // 實(shí)際通過(guò)調(diào)用此函數(shù)實(shí)現(xiàn)
}

func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) {
	if buf != nil && len(buf) == 0 { // 當(dāng)buf非空或者長(zhǎng)度0,panic
		panic("empty buffer in CopyBuffer")
	}
	return copyBuffer(dst, src, buf) // 繼續(xù)往下調(diào)用
}


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 { // 源實(shí)現(xiàn)了writeTo就可以直接調(diào)用結(jié)束
		return wt.WriteTo(dst)
	}
	// Similarly, if the writer has a ReadFrom method, use it to do the copy.
	if rt, ok := dst.(ReaderFrom); ok { // 目標(biāo)實(shí)現(xiàn)了readFrom,也可以直接調(diào)用結(jié)束
		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) // buf空時(shí),創(chuàng)建buf
	}
        // 開(kāi)啟循環(huán)內(nèi)容讀取
	for {
		nr, er := src.Read(buf) // 從源中讀取內(nèi)容到buf中
		if nr > 0 {
			nw, ew := dst.Write(buf[0:nr]) // 目標(biāo)w從buf中寫(xiě)入內(nèi)容
			if nw < 0 || nr < nw {
				nw = 0
				if ew == nil {
					ew = errInvalidWrite
				}
			}
			written += int64(nw) // 更新寫(xiě)入長(zhǎng)度
			if ew != nil { // 寫(xiě)入返回err,退出循環(huán)
				err = ew
				break
			}
			if nr != nw { // 讀取與寫(xiě)入長(zhǎng)度不等,退出
				err = ErrShortWrite
				break
			}
		}
		if er != nil { // 讀err非空,退出
			if er != EOF {
				err = er
			}
			break
		}
	}
	return written, err // 返回寫(xiě)入長(zhǎng)度及err
}

通過(guò)源碼走讀,我們可以看到,在函數(shù)中傳入 Writer 作為目標(biāo)寫(xiě)入對(duì)象,傳入 Reader 作為源讀取對(duì)象,如果 Reader 對(duì)象實(shí)現(xiàn) WriteTo 方法,我們可以直接調(diào)用此完成 copy, 或者是 Writer 對(duì)象實(shí)現(xiàn)了 ReadFrom 方法,我們可以直接調(diào)用此完成 copy,都沒(méi)有實(shí)現(xiàn),就只有通過(guò) buf 作為中轉(zhuǎn),通過(guò)循環(huán),先從源讀取內(nèi)容,再寫(xiě)入目標(biāo)對(duì)象中,最后返回整個(gè)內(nèi)容的長(zhǎng)度,當(dāng)然其中也有相關(guān)錯(cuò)誤處理,這里不做討論。

接下來(lái) io包 中提供的另外的寫(xiě)入操作實(shí)現(xiàn):

// io.WriteString()
func WriteString(w Writer, s string) (n int, err error) {
	if sw, ok := w.(StringWriter); ok { // 如w實(shí)現(xiàn)了 StringWriter,則調(diào)用相關(guān)方法實(shí)現(xiàn)寫(xiě)入
		return sw.WriteString(s)
	}
	return w.Write([]byte(s)) // 作為兜底,w對(duì)象是肯定實(shí)現(xiàn)了 Write() 方法,所以調(diào)用此方法實(shí)現(xiàn)寫(xiě)入
}

從上面代碼可以看到,該實(shí)現(xiàn)邏輯簡(jiǎn)單,具體見(jiàn)注釋。

io包實(shí)現(xiàn)讀寫(xiě)操作 準(zhǔn)備:

  • file.txt,作為讀取源,然后再寫(xiě)入其他文件中 寫(xiě)操作,我們實(shí)現(xiàn)了2種,一種 io.Copy(),一種 io.WriteString(),具體使用見(jiàn)下面代碼:

 

func ioRW()  {
	// read
	f, err := os.Open("D:\\demo1\\src\\demo23\\go-io\\file\\file.txt")
	defer f.Close()
	if err != nil {
		fmt.Printf("err: %s\n", err)
		return
	}
	b, err := io.ReadAll(f)
	if err != nil {
		fmt.Printf("err: %s\n", err)
		return
	}
	fmt.Printf("ioRW read content: \n%s\n", b)

	// write
	// 1.io.Copy()
	fw, err := os.Create("io_w.txt")
	defer fw.Close()
	n, err := io.Copy(fw, strings.NewReader(string(b)))
	if err != nil {
		fmt.Printf("err: %s\n", err)
		return
	}
	// 2.io.WriteString()
	fw_1, _ := os.Create("io_w_1.txt")
	defer fw_1.Close()
	n, err := io.WriteString(fw_1, string(b))
	if err != nil {
		fmt.Printf("err: %s\n", err)
		return
	}

	fmt.Printf("ioRW write size: %d\n", n)
}

2.io.ioutil包實(shí)現(xiàn)讀寫(xiě)操作

所謂 util,肯定是作為工具使用,怎么方便怎么來(lái),我們甚至通過(guò)文件名就可以完成操作,具體實(shí)現(xiàn)細(xì)節(jié)我們不關(guān)心,總之它實(shí)現(xiàn)了這些功能。

注意 由于我使用的 go 1.19,在源碼中,明確聲明在 go 1.16 后,逐漸棄用了,所以使用高版本的 go 時(shí)要注意這個(gè)問(wèn)題,這里為了增加源碼的了解熟悉,也拿出來(lái)作為分享。

讀操作

// Deprecated: As of Go 1.16, this function simply calls io.ReadAll.
func ReadAll(r io.Reader) ([]byte, error) {
	return io.ReadAll(r)
}

// Deprecated: As of Go 1.16, this function simply calls os.ReadFile.
func ReadFile(filename string) ([]byte, error) {
	return os.ReadFile(filename)
}

在 ReadAll 中,實(shí)際也是調(diào)用上面的 io.ReadAll(),這里不贅述,在 ReadFile 中,我們傳入個(gè)文件名,就可以讀取到整個(gè)字節(jié)內(nèi)容,實(shí)際它也是調(diào)用 os.ReadFile() 實(shí)現(xiàn),后面再討論 os包。

寫(xiě)操作

// Deprecated: As of Go 1.16, this function simply calls os.WriteFile.
func WriteFile(filename string, data []byte, perm fs.FileMode) error {
	return os.WriteFile(filename, data, perm)
}

可以看到,這里也是調(diào)用了 os.WriteFile() 實(shí)現(xiàn)文件的寫(xiě)入,只需要我們傳入待寫(xiě)入的文件名,寫(xiě)入的字節(jié)數(shù)組,以及寫(xiě)入文件的權(quán)限,是不是很簡(jiǎn)單。

代碼實(shí)用

func ioutilRW()  {
	// read
	b, err := ioutil.ReadFile("D:\\demo1\\src\\demo23\\go-io\\file\\file.txt")
	if err != nil {
		fmt.Printf("err: %s\n", err)
		return
	}

	fmt.Printf("ioutilRW read content: \n%s\n", b)

	// write
	err = ioutil.WriteFile("ioutilRW_w.txt", b, 664)
	if err != nil {
		fmt.Printf("err: %s\n", err)
		return
	}
	fmt.Println("ioutilRW write err: ", err)
}

上面的讀取與寫(xiě)入操作實(shí)際很簡(jiǎn)單,代碼操作沒(méi)難度,相信你一看就懂。

今天我們通過(guò) io.Reader/io.Writer 接口了解了實(shí)現(xiàn)了該接口的都可以作為相關(guān)對(duì)象,通過(guò) io包也實(shí)現(xiàn)了文件的讀寫(xiě),后面我們會(huì)陸續(xù)分享基于 os/bufio/bytes/strings 的讀寫(xiě)操作,畢竟 IO 范圍還是很廣,文件IO只是一部分。

到此這篇關(guān)于一文詳解golang通過(guò)io包進(jìn)行文件讀寫(xiě)的文章就介紹到這了,更多相關(guān)golang通過(guò)io包文件讀寫(xiě)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Golang使用Gin框架實(shí)現(xiàn)HTTP上傳文件過(guò)程介紹

    Golang使用Gin框架實(shí)現(xiàn)HTTP上傳文件過(guò)程介紹

    由于需求中有文件上傳這一個(gè)需求,在這里我們就學(xué)習(xí)一下go語(yǔ)言如何上傳文件。本文主要通過(guò)表單的方式進(jìn)行文件上傳操作,本文實(shí)例為大家分享了Go實(shí)現(xiàn)文件上傳操作的具體代碼,供大家參考,具體內(nèi)容如下
    2023-04-04
  • 詳解Go 結(jié)構(gòu)體格式化輸出

    詳解Go 結(jié)構(gòu)體格式化輸出

    這篇文章主要介紹了Go 結(jié)構(gòu)體格式化輸出的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)go語(yǔ)言,感興趣的朋友可以了解下
    2020-08-08
  • gomod包依賴(lài)管理工具使用詳解

    gomod包依賴(lài)管理工具使用詳解

    這篇文章主要為大家介紹了gomod如何解決包管理問(wèn)題使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • 淺析Go語(yǔ)言中數(shù)組的這些細(xì)節(jié)

    淺析Go語(yǔ)言中數(shù)組的這些細(xì)節(jié)

    這篇文章主要為大家詳細(xì)介紹了Go語(yǔ)言中數(shù)組一些細(xì)節(jié)的相關(guān)資料,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Go語(yǔ)言有一定的幫助,需要的可以了解一下
    2022-11-11
  • 詳解Go語(yǔ)言中空結(jié)構(gòu)體的慣用法

    詳解Go語(yǔ)言中空結(jié)構(gòu)體的慣用法

    空結(jié)構(gòu)體在 Go 編程中有著廣泛的應(yīng)用,本文將詳細(xì)探討空結(jié)構(gòu)體的幾種典型用法,并解釋為何它們?cè)谔囟▓?chǎng)景下非常有用,希望對(duì)大家有所幫助
    2024-11-11
  • Go語(yǔ)言七篇入門(mén)教程二程序結(jié)構(gòu)與數(shù)據(jù)類(lèi)型

    Go語(yǔ)言七篇入門(mén)教程二程序結(jié)構(gòu)與數(shù)據(jù)類(lèi)型

    這篇文章主要為大家介紹了Go語(yǔ)言的程序結(jié)構(gòu)與數(shù)據(jù)類(lèi)型,本篇文章是Go語(yǔ)言七篇入門(mén)系列文,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2021-11-11
  • golang守護(hù)進(jìn)程用法示例

    golang守護(hù)進(jìn)程用法示例

    這篇文章主要介紹了golang守護(hù)進(jìn)程用法,結(jié)合實(shí)例形式分析了Go語(yǔ)言守護(hù)進(jìn)程的具體實(shí)現(xiàn)與使用技巧,需要的朋友可以參考下
    2016-07-07
  • Golang中正則表達(dá)式語(yǔ)法及相關(guān)示例

    Golang中正則表達(dá)式語(yǔ)法及相關(guān)示例

    正則表達(dá)式是一種用于匹配和操作文本的強(qiáng)大工具,它使用特殊的字符和語(yǔ)法來(lái)定義模式,下面這篇文章主要給大家介紹了關(guān)于Golang中正則表達(dá)式語(yǔ)法及相關(guān)示例的相關(guān)資料,需要的朋友可以參考下
    2024-05-05
  • Go中的fuzz模糊測(cè)試使用實(shí)戰(zhàn)詳解

    Go中的fuzz模糊測(cè)試使用實(shí)戰(zhàn)詳解

    這篇文章主要為大家介紹了Go中的fuzz模糊測(cè)試使用實(shí)戰(zhàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • 關(guān)于Golang標(biāo)準(zhǔn)庫(kù)flag的全面講解

    關(guān)于Golang標(biāo)準(zhǔn)庫(kù)flag的全面講解

    這篇文章主要介紹了關(guān)于Golang標(biāo)準(zhǔn)庫(kù)flag的全面講解,這個(gè)庫(kù)的代碼量只有1000行左右,卻提供了非常完善的命令行參數(shù)解析功能,更多相關(guān)內(nèi)容需要的朋友可以參考一下
    2022-09-09

最新評(píng)論

宁津县| 曲沃县| 阿克苏市| 星座| 湾仔区| 常州市| 扶绥县| 乐亭县| 湛江市| 甘肃省| 朝阳县| 南宁市| 正宁县| 隆林| 大石桥市| 社会| 利辛县| 项城市| 兖州市| 仁布县| 龙里县| 文昌市| 桦南县| 新闻| 宜宾县| 昌都县| 高雄县| 马关县| 大姚县| 黑山县| 报价| 开平市| 柳河县| 阿图什市| 余干县| 阿拉善右旗| 边坝县| 凌海市| 建宁县| 景泰县| 茂名市|