目录

Go文件读写和IO操作

IO接口

io.Reader 读IO接口

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

io.Writer 写IO接口

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

io.Closer 关闭IO接口

type Closer interface {
	Close() error
}

文件读取

方式一: 无缓冲直接读取

func fileDemo1() {
	file, err := os.Open("/go-test-learn/io/t1.go")
	CheckError("", err)
	defer file.Close()

	content := []byte{}
	buf := make([]byte, 100) //每次读取的最大byte数组
	for {
        n, err := file.Read(buf) //返回真实读取的数据字节大小 (<=len(buf))
		if err == io.EOF { //err=io.EOF表示已经读取到结束了
			break
		}
		CheckError("", err)
		content = append(content, buf[:n]...)
	}
	//fmt.Println(string(content))
}

方式二: 缓冲IO

缓冲IO在调用Read()时会预先读取一部分数据到自己的缓存区,这样就不需要每次都调用Read去读取数据了,直接返回缓存区里的数据即可,只有缓存区里的数据不足才会调用底层的Read

func fileDemo2() {
	file, err := os.Open("/go-test-learn/io/t1.go")
	CheckError("", err)
	defer file.Close()
    
    //包装file为缓冲reader
	reader := bufio.NewReader(file) 

	content := []byte{}
	buf := make([]byte, 100)

	for {
		n, err := reader.Read(buf)
		if err == io.EOF {
			break
		}
		CheckError("", err)
		content = append(content, buf[:n]...)
	}
	//fmt.Println(string(content))
}

方式三: io.ReadAll()方法,ioutil.ReadAll()也是间接调用此方法

func fileDemo3() {
	file, err := os.Open("/home/pb/data/go-code/go-test-learn/io/t1.go")
	CheckError("", err)
	defer file.Close()
	
    //也是有缓冲的读取
	content, _ := io.ReadAll(file) //ioutil.ReadAll(file)同理
	if err == nil {
		fmt.Println(string(content))
	}
}

文件按行读取

func fileDemo5() {
	file, err := os.Open("/go-test-learn/io/t1.go")
	CheckError("", err)
	defer file.Close()

	reader := bufio.NewReader(file)
	for {
        //读取到\n就结束  返回的string包含\n
		line, err := reader.ReadString('\n')
		if err == io.EOF {
			break
		}
		CheckError("", err)
		fmt.Print(line)
	}
}

文件写入

方式一: ioutil.WriteFile()

func writeDemo1() {
	content := []byte("hello,world")
    //文件不存在的话会自动创建 存在的话则会覆盖里面的内容
	ioutil.WriteFile("/io/a.txt", content, 0644) 
}

方式二: io.WriteString() 需要预先打开文件

func writeDemo2() {
	file, err := os.OpenFile("/go-test-learn/io/a.txt", os.O_WRONLY|os.O_APPEND, 0644)
	CheckError("", err)
	defer file.Close()
    
    //返回写入的字节大小
	_, err = io.WriteString(file, "hello,world\n")
	fmt.Println(err)
}

方式三: Write() 直接写入

func writeDemo3() {
	file, err := os.OpenFile("/home/pb/data/go-code/go-test-learn/io/a.txt", os.O_WRONLY|os.O_APPEND, 0644)
	CheckError("", err)
	defer file.Close()
    
	file.Write([]byte("hello,go\n"))
}

方式四: bufio.Writer缓冲写入

写入的时候不会立即调用Write()写入,而是先写入到缓冲区里面,直到缓存区写满了才调用Write()一次性写入

func writeDemo4() {
	file, err := os.OpenFile("/go-test-learn/io/a.txt", os.O_WRONLY|os.O_APPEND, 0644)
	CheckError("", err)
	defer file.Close()

	writer := bufio.NewWriter(file) //包装为有缓冲的Writer
	writer.WriteString("hello,java\n")
    writer.Flush() //需要调用Flush()刷新,否则可能不会被写入
}

几个特殊的IO方法

io.ReadAll() 读取reader中的全部数据

content, _ := io.ReadAll(file) //ioutil.ReadAll(file)同理

io.ReadFull 填充传入的字节数组,返回读取的字节数

  • 如果传入的字节数组空间足够大则errorErrUnexpectedEOF,并且返回实际读取的字节数
  • 如果传入的字节数组不足,则errornil,并且返回实际读取的字节数
func main() {
	file, _ := os.Open("/a.txt")
	data := make([]byte, 20)
	n, err := io.ReadFull(file, data)
	fmt.Println(string(data), n, err == io.ErrUnexpectedEOF)
}

io.Copy 负责在两个IO之间copy数据

func main() {
	file1, _ := os.Open("/a.txt")
	file2, _ := os.OpenFile("/b.txt",os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0664)
	defer file1.Close()
	defer file2.Close()

	reader := bufio.NewReader(file1)
	writer := bufio.NewWriter(file2)
    //文件复制: 将file1的内容copy到file2中
	n, err := io.Copy(writer, reader) //返回copy的字节数
}

参考

Golang 读、写文件