问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

golangwriter

发布网友 发布时间:2024-10-02 00:47

我来回答

1个回答

热心网友 时间:2024-10-29 18:07

Golang:I/O操作,千万不要小瞧这些知识点

I/O操作也叫输入输出操作。其中I是指Input,O是指Output,用于读或者写数据的,有些语言中也叫流操作,是指数据通信的通道。

Golang标准库对IO的抽象非常精巧,各个组件可以随意组合,可以作为接口设计的典范。

io包中提供I/O原始操作的一系列接口。它主要包装了一些已有的实现,如os包中的那些,并将这些抽象成为实用性的功能和一些其他相关的接口。

在io包中最重要的是两个接口:Reader和Writer接口,首先来介绍这读的操作。

Reader接口的定义,Read()方法用于读取数据。

Read将len(p)个字节读取到p中。它返回读取的字节数n(0=n=len(p))以及任何遇到的错误。即使Read返回的nlen(p),它也会在调用过程

中使用p的全部作为暂存空间。若一些数据可用但不到len(p)个字节,Read会照例返回可用的东西,而不是等待更多。

当Read在成功读取n0个字节后遇到一个错误或EOF情况,它就会返回读取的字节数,这种一般情况的一个例子就是Reader在输入流结束时会返回一个非零的字节数,可能的返回不是err==EOF就是err==nil。无论如何,下一个Read都应当返回0、EOF。

调用者应当总在考虑到错误err前处理n0的字节。这样做可以在读取一些字节,以及允许的EOF行为后正确地处理I/O错误。

Read的实现会阻止返回零字节的计数和一个nil错误,调用者应将这种情况视作空操作。

ReaderFrom接口的定义,封装了基本的ReadFrom方法。

ReadFrom从r中读取数据到对象的数据流中,直到r返回EOF或r出现读取错误为止,返回值n是读取的字节数,返回值err就是r的返回值err。

定义ReaderAt接口,ReaderAt接口封装了基本的ReadAt方法

ReadAt从对象数据流的off处读出数据到p中,忽略数据的读写指针,从数据的起始位置偏移off处开始读取,如果对象的数据流只有部分可用,不足以填满p,则ReadAt将等待所有数据可用之后,继续向p中写入,直到将p填满后再返回。

在这点上ReadAt要比Read更严格,返回读取的字节数n和读取时遇到的错误,如果nlen(p),则需要返回一个err值来说明,为什么没有将p填满(比如EOF),如果n=len(p),而且对象的数据没有全部读完,则err将返回nil,如果n=len(p),而且对象的数据刚好全部读完,则err将返回EOF或者nil(不确定)

file类是在os包中的,封装了底层的文件描述符和相关信息,同时封装了Read和Write的实现。

读取文件中的数据:

Writer接口的定义,Write()方法用于写出数据。

Write将len(p)个字节从p中写入到基本数据流中。它返回从p中被写入的字节数n(0=n=len(p))以及任何遇到的引起写入提前停止的错误。若Write返回的nlen(p),它就必须返回一个非nil的错误。Write不能修改此切片的数据,即便它是临时的。

Seeker接口的定义,封装了基本的Seek方法。

Seeker用来移动数据的读写指针,Seek设置下一次读写操作的指针位置,每次的读写操作都是从指针位置开始的。

whence的含义:

如果whence为0:表示从数据的开头开始移动指针

如果whence为1:表示从数据的当前指针位置开始移动指针

如果whence为2:表示从数据的尾部开始移动指针

offset是指针移动的偏移量

返回移动后的指针位置和移动过程中遇到的任何错误

WriterTo接口的定义,封装了基本的WriteTo方法。

WriterTo将对象的数据流写入到w中,直到对象的数据流全部写入完毕或遇到写入错误为止。返回值n是写入的字节数,返回值err就是w的返回值err。

定义WriterAt接口,WriterAt接口封装了基本的WriteAt方法

WriteAt将p中的数据写入到对象数据流的off处,忽略数据的读写指针,从数据的起始位置偏移off处开始写入,返回写入的字节数和写入时遇到的错误。如果nlen(p),则必须返回一个err值来说明为什么没有将p完全写入

file类是在os包中的,封装了底层的文件描述符和相关信息,同时封装了Read和Write的实现。

写出数据到本地文件:

Golang将日志同时输出到控制台和文件

日常开发当中需要将golang的log包打印的日志同时输出到控制台和文件,应该如何解决这个问题?

log包可以通过SetOutput()方法指定日志输出的方式(Writer),但是只能指定一个输出的方式(Writer)。我们利用io.MultiWriter()将多个Writer拼成一个Writer使用的特性,把log.Println()输出的内容分流到控制台和文件当中。

原文地址

详解golang中bufio包的实现原理

最近用golang写了一个处理文件的脚本,由于其中涉及到了文件读写,开始使用golang中的io包,后来发现golang中提供了一个bufio的包,使用这个包可以大幅提高文件读写的效率,于是在网上搜索同样的文件读写为什么bufio要比io的读写更快速呢?根据网上的资料和阅读源码,以下来详细解释下bufio的高效如何实现的。

bufio包介绍?

bufio包实现了有缓冲的I/O。它包装一个io.Reader或io.Writer接口对象,创建另一个也实现了该接口,且同时还提供了缓冲和一些文本I/O的帮助函数的对象。

以上为官方包的介绍,在其中我们能了解到的信息如下:

bufio是通过缓冲来提高效率

简单的说就是,把文件读取进缓冲(内存)之后再读取的时候就可以避免文件系统的io从而提高速度。同理,在进行写操作时,先把文件写入缓冲(内存),然后由缓冲写入文件系统。看完以上解释有人可能会表示困惑了,直接把内容-文件和内容-缓冲-文件相比,缓冲区好像没有起到作用嘛。其实缓冲区的设计是为了存储多次的写入,最后一口气把缓冲区内容写入文件。下面会详细解释

bufio封装了io.Reader或io.Writer接口对象,并创建另一个也实现了该接口的对象

io.Reader或io.Writer接口实现read()和write()方法,对于实现这个接口的对象都是可以使用这两个方法的

bufio包实现原理

bufio源码分析

Reader对象

bufio.Reader是bufio中对io.Reader的封装

//Readerimplementsbufferingforanio.Readerobject.

typeReaderstruct{

??buf????[]byte

??rd?????io.Reader//readerprovidedbytheclient

??r,w????int???//bufreadandwritepositions

??err????error

??lastByte??int

??lastRuneSizeint

}

bufio.Read(p[]byte)相当于读取大小len(p)的内容,思路如下:

当缓存区有内容的时,将缓存区内容全部填入p并清空缓存区

当缓存区没有内容的时候且len(p)len(buf),即要读取的内容比缓存区还要大,直接去文件读取即可

当缓存区没有内容的时候且len(p)len(buf),即要读取的内容比缓存区小,缓存区从文件读取内容充满缓存区,并将p填满(此时缓存区有剩余内容)

以后再次读取时缓存区有内容,将缓存区内容全部填入p并清空缓存区(此时和情况1一样)

以下是源码

//Readreadsdataintop.

//Itreturnsthenumberofbytesreadintop.

//ThebytesaretakenfromatmostoneReadontheunderlyingReader,

//hencenmaybelessthanlen(p).

//AtEOF,thecountwillbezeroanderrwillbeio.EOF.

func(b*Reader)Read(p[]byte)(nint,errerror){

??n=len(p)

??ifn==0{

????return0,b.readErr()

??}

??ifb.r==b.w{

????ifb.err!=nil{

??????return0,b.readErr()

????}

????iflen(p)=len(b.buf){

??????//Largeread,emptybuffer.

??????//Readdirectlyintoptoavoidcopy.

??????n,b.err=b.rd.Read(p)

??????ifn0{

????????panic(errNegativeRead)

??????}

??????ifn0{

????????b.lastByte=int(p[n-1])

????????b.lastRuneSize=-1

??????}

??????returnn,b.readErr()

????}

????//Oneread.

????//Donotuseb.fill,whichwillloop.

????b.r=0

????b.w=0

????n,b.err=b.rd.Read(b.buf)

????ifn0{

??????panic(errNegativeRead)

????}

????ifn==0{

??????return0,b.readErr()

????}

????b.w+=n

??}

??//copyasmuchaswecan

??n=copy(p,b.buf[b.r:b.w])

??b.r+=n

??b.lastByte=int(b.buf[b.r-1])

??b.lastRuneSize=-1

??returnn,nil

}

说明:

reader内部通过维护一个r,w即读入和写入的位置索引来判断是否缓存区内容被全部读出

Writer对象

bufio.Writer是bufio中对io.Writer的封装

//Writerimplementsbufferingforanio.Writerobject.

typeWriterstruct{

??errerror

??buf[]byte

??n?int

??wrio.Writer

}

bufio.Write(p[]byte)的思路如下

判断buf中可用容量是否可以放下p

如果能放下,直接把p拼接到buf后面,即把内容放到缓冲区

如果缓冲区的可用容量不足以放下,且此时缓冲区是空的,直接把p写入文件即可

如果缓冲区的可用容量不足以放下,且此时缓冲区有内容,则用p把缓冲区填满,把缓冲区所有内容写入文件,并清空缓冲区

判断p的剩余内容大小能否放到缓冲区,如果能放下(此时和步骤1情况一样)则把内容放到缓冲区

如果p的剩余内容依旧大于缓冲区,(注意此时缓冲区是空的,情况和步骤2一样)则把p的剩余内容直接写入文件

//Writewritesthecontentsofpintothebuffer.

//Itreturnsthenumberofbyteswritten.

//Ifnnlen(p),italsoreturnsanerrorexplaining

//whythewriteisshort.

func(b*Writer)Write(p[]byte)(nnint,errerror){

??forlen(p)b.Available()b.err==nil{

????varnint

????ifb.Buffered()==0{

??????//Largewrite,emptybuffer.

??????//Writedirectlyfromptoavoidcopy.

??????n,b.err=b.wr.Write(p)

????}else{

??????n=copy(b.buf[b.n:],p)

??????b.n+=n

??????b.flush()

????}

????nn+=n

????p=p[n:]

??}

??ifb.err!=nil{

????returnnn,b.err

??}

??n:=copy(b.buf[b.n:],p)

??b.n+=n

??nn+=n

??returnnn,nil

}

说明:

b.wr存储的是一个io.writer对象,实现了Write()的接口,所以可以使用b.wr.Write(p)将p的内容写入文件

b.flush()会将缓存区内容写入文件,当所有写入完成后,因为缓存区会存储内容,所以需要手动flush()到文件

b.Available()为buf可用容量,等于len(buf)-n

下图解释的是其中一种情况,即缓存区有内容,剩余p大于缓存区

golang文件操作摘抄

译者按:rename和move原理一样

译者按:熟悉Linux的读者应该很熟悉权限模式,通过Linux命令chmod可以更改文件的权限

补充了原文未介绍的flag

一个普通的文件是一个指向硬盘的inode的地方。硬链接创建一个新的指针指向同一个地方。只有所有的链接被删除后文件才会被删除。硬链接只在相同的文件系统中才工作。你可以认为一个硬链接是一个正常的链接。

symboliclink,又叫软连接,和硬链接有点不一样,它不直接指向硬盘中的相同的地方,而是通过名字引用其它文件。他们可以指向不同的文件系统中的不同文件。并不是所有的操作系统都支持软链接。

复制文件

可以使用os包写入一个打开的文件。因为Go可执行包是静态链接的可执行文件,你import的每一个包都会增加你的可执行文件的大小。其它的包如io、`ioutil`、`bufio`提供了一些方法,但是它们不是必须的。

ioutil包有一个非常有用的方法WriteFile()可以处理创建/打开文件、写字节slice和关闭文件一系列的操作。如果你需要简洁快速地写字节slice到文件中,你可以使用它。

bufio包提供了带缓存功能的writer,所以你可以在写字节到硬盘前使用内存缓存。当你处理很多的数据很有用,因为它可以节省操作硬盘I/O的时间。在其它一些情况下它也很有用,比如你每次写一个字节,把它们攒在内存缓存中,然后一次写入到硬盘中,减少硬盘的磨损以及提升性能。

读取最多N个字节

os.File提供了文件操作的基本功能,而io、ioutil、bufio提供了额外的辅助函数。

有缓存写也有缓存读。缓存reader会把一些内容缓存在内存中。它会提供比os.File和io.Reader更多的函数,缺省的缓存大小是4096,最小缓存是16。

Scanner是bufio包下的类型,在处理文件中以分隔符分隔的文本时很有用。通常我们使用换行符作为分隔符将文件内容分成多行。在CSV文件中,逗号一般作为分隔符。os.File文件可以被包装成bufio.Scanner,它就像一个缓存reader。我们会调用Scan()方法去读取下一个分隔符,使用Text()或者Bytes()获取读取的数据。

分隔符可以不是一个简单的字节或者字符,有一个特殊的方法可以实现分隔符的功能,以及将指针移动多少,返回什么数据。如果没有定制的SplitFunc提供,缺省的ScanLines会使用newline字符作为分隔符,其它的分隔函数还包括ScanRunes和ScanWords,皆在bufio包中。

打包(zip)文件

其它

临时文件和目录

ioutil提供了两个函数:TempDir()和TempFile()。使用完毕后,调用者负责删除这些临时文件和文件夹。有一点好处就是当你传递一个空字符串作为文件夹名的时候,它会在操作系统的临时文件夹中创建这些项目(/tmponLinux)。os.TempDir()返回当前操作系统的临时文件夹。

上面的例子复制整个文件内容到内存中,传递给hash函数。另一个方式是创建一个hashwriter,使用Write、WriteString、Copy将数据传给它。下面的例子使用md5hash,但你可以使用其它的Writer。

聊聊golang的zap的ZapKafkaWriter

本文主要研究一下golang的zap的ZapKafkaWriter

WriteSyncer内嵌了io.Writer接口,定义了Sync方法;Sink接口内嵌了zapcore.WriteSyncer及io.Closer接口;ZapKafkaWriter实现Sink接口及zapcore.WriteSyncer接口,其Write方法直接将data通过kafka发送出去。

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
民事公告送达期限是多长时间 有没有能在平板上可以下载生活大爆炸的资源,或播放器离线观看? 生活大爆炸1-8季完整版 115网盘 百度云都可以 谢了 D:\My Documents\My Pictures\d16ea14552a02519cffca397.jpg这个韩国女... 安阳市从三角湖到北晨家园坐几路公交车 安阳北辰家园附近到郑州的物流? 从安阳文化宫到北城家园坐几路公交 让子弹飞现在票房多少了?拿国产第一了吗? 疯狂猜成语第24关 一把刀和一个斧头 前男友要见回前女友,但是他说只是当她是朋友而已,但是有一件事情就 Go工程化实践:用kafka-go实现发布订阅 角鱼薄釜壶龟毛日中中游月冰如兔履怎么组成语 golang接口的使用场景? Golang正确使用kafka的姿势-细节决定成败 男人遗精是什么 男人长期遗精会带来哪些危害? 坐高铁可以买两张一起的票,但其中一个人要坐更多的站,请问他可以在上车... 路吉星k10电子狗怎么样 猎豹QQ浏览器都打不开网页,360浏览器就打得开 网页经常打不开,没反应,QQ空间开启不了,图片也是,但是猎豹测速20M 为什么电脑能上qq 猎豹浏览器能用 但其他的软件都显示连不上网 太平洋乐享百万医疗保险怎么退保? 太平洋乐享百万医疗保险怎么退保? 太平洋乐享百万医疗保险可以退吗? 男,22岁。上周一在某招聘APP投简历,一个女的人事和我联系,她头像漂亮... 我在网上某某app投的简历,之后有两个人打电话,都是一家公司的面试,会不... 自学会计该怎么入手难度大吗 会计自学要什么学历 自学初级会计需要什么 上海通报3例死亡病例详情:均为高龄未接种疫苗,接种疫苗的必要性有哪些... 喜欢和占有欲有什么区别啊?? ...他妈和我吵说不行我们在一起,后来我说了要和他在一起,就 想问下为什么韩语里ㄷ,ㅈ,ㅂ,ㄱ开头有时候不读原来的音标,有规... 韩语变音规律,还有ㅈㄱㄷㅂ,四个字母放在开头和句子中读音不... 韩语辅音“ㄹ”、“ㅂ”、“ㄱ”、“ㄷ”读音问题 昨晚梦见我们生活老师给我介绍男朋友,男方妈妈想见到我,让我家亲戚一... 韩语"ㅂㅃㅈㅉㄷㄸㄱㄲㅅㅆ"的发音的问题 ...了个男朋友,去见未来的公公,然后就住在男方家了,结果起了一身的水 ... 猫的尾巴尖坏死干了 为什么不能给猫咪塞尾巴呢? 这3招教你如何在淘宝上买茶不会被坑! 广州哪里有好的蛋黄月饼 微信小程序登陆入口在哪? 我电脑中出现了文件名PreScan.running的文件,这是什么啊,是病毒吗? 随手问卷提现怎么不到账? 随手问卷app靠谱吗我用积分兑换20元,刚兑换,还没到账,关键是绑定了手机... 随手问卷可以注销吗? 随手问卷的提交是什么意思 二胎备孕要做好哪些准备 这五个方面一定要注意 为什么我的成绩直线下降