不带缓冲区读取
读文件就使用这个函数
func (f *File) Read(b []byte) (n int, err error)
content := make([]byte,3) //只能读三个字节,最后打印的是字符串对应于int的值,初始化为3个0值
fmt.Println(file.Read(content))
fmt.Println(len(content),cap(content),content,string(content))//字节转化为字符使用string()
3 读取了多少字节 <nil>
3 3 [104 101 108] hel
因为字节切片大小为3,所以是一个不断覆盖的过程
如果要准确打印读到的字节,可以使用如下:
content := make([]byte,3)
n,err := file.Read(content)
if err == nil{
fmt.Println(len(content),cap(content),content,string(content[:n]))
}
如果读取到内容,err的值为nil,如果读取到文件结束了返回的是EOF
n,err := file.Read(content)
fmt.Println(len(content),cap(content),content,n,err,string(content[:n]))
n,err = file.Read(content)
fmt.Println(len(content),cap(content),content,n,err,string(content[:n]))
3 3 [104 0 0] 1 <nil> h
3 3 [104 0 0] 0 EOF
修改一下,如果文件读取完毕之后
content := make([]byte,3)
for{
n,err := file.Read(content)
if err != nil{
//EOF 标识文件读取结束
//非 EOF的时候
if err != io.EOF{
fmt.Println(err)
}
break
}
fmt.Printf("%s",string(content[:n]))
}
file.Close()
如果是文本内容,可以使用切片处理也可以使用string来处理。上面是读取字节切片的方式来处理,字节切片可以处理文本文件,只不过在打印的时候,打印成字符串了,这个字节切片能不能正常的转化为字符串,一个字符串在获取切片的时候是按照字节去处理的,这个时候正好写了3,在unicode的编码的时候占用3个字节,如果换成2就会转化出来的中文有乱码的。
还有在读取的时候是和系统调用时有关系的file.Read(content),每次读取的时候是有系统调用,如果读取的时候长度设置的很小的时候,那么系统调用的频率会很高,系统调用多了性能就会差,但是设置为无限大也是不可能的,因为这个也是消耗内存的。
对文本文件处理有两种方式,将所有的字节读出来,然后转化为字符串,或者每次读取出来是字符。
代码是从上到下执行的,如果中间程序发生错误的时候后面代码就执行不到了,如何保证函数在退出的时候一定将文件关闭,只要函数退出,不管中间是否发生错误都会进行执行。(defer是在函数退出的时候执行,在打开文件的时候,没有出现错误,然后延时关闭,后面再去读,不管后面是否出现错误都会执行文件关闭这个动作)
path := "text.txt"
file,err := os.Open(path)
fmt.Println(file,err)
if err != nil{
return
}
defer file.Close()
content := make([]byte,5)
for{
n,err := file.Read(content)
if err != nil{
//EOF 标识文件读取结束
//非 EOF的时候
if err != io.EOF{
fmt.Println(err)
}
break
}
fmt.Printf("%s",string(content[:n]))
}
带缓冲区读取 bufio.NewReader reader.ReadString
读取文件的内容并显示在终端(带缓冲区的方式,这样适合读取比较大的文件)
使用os.Open,file.Close,bufio.NewReader(),reader.ReadString() 函数和方法
type File
func (f *File) Read(b []byte) (n int, err error)
bufio包
func NewReader(rd io.Reader) *Reader
NewReader创建一个具有默认大小缓冲、从r读取的*Reader。
type Reader interface {
Read(p []byte) (n int, err error)
}
type Reader struct {
buf []byte //可以看到里面带有缓冲
rd io.Reader
r, w int
err error
lastByte int
lastRuneSize int
}
const (
defaultBufSize = 4096
)
这个reader defaultBufSize = 4096 默认的缓冲区的大小是4096字节。
在读取文件的时候,并不是一次性将文件读取到内存,而是读一部分,然后处理一部分,这样可以处理一些比较大的文件,有了这个Reader就可以循环的读取文件的内容。
func (*Reader) ReadString
这里的error为io.EOF,这个就代表读到文件的末尾了
func main() {
file,err := os.Open("test.txt")
if err != nil{
return
}
//当函数退出时候要及时关闭file句柄,否则有内存泄漏
defer func() {
err = file.Close()
if err != nil {
fmt.Println("file close error:",err)
}
}()
//创建一个*Reader,这个是带缓冲的,指针类型,这个在bufio包里面
reader := bufio.NewReader(file) //reader和file文件绑定了
for {
str,err := reader.ReadString('\n') //读到一个换行就结束,同时会将换行读取进去
fmt.Printf("%s", str)
if err == io.EOF { //io.EOF表示文件的末尾
break
}
}
}