代码改变世界

golang-标准库文件操作

2023-02-26 18:00  dribs  阅读(29)  评论(0编辑  收藏  举报
package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

func example1() {
	filename := "e:/test.txt" //内容为abc
	//Open是只读方式打开 实际是调用的OpenFile(name, O_RDONLY, 0)
	if f, err := os.Open(filename); err == nil {
		defer f.Close()
		fmt.Printf("%T,%[1]v\n", f)
		buffer := make([]byte, 2)
		for {
			n, err := f.Read(buffer)
			fmt.Println(n, err)
			if n == 0 {
				break //什么都没读取到,说明读到了文件的结尾EOF
			}
			////97 98
			////99 98 buffer 读abc 以2字节读取会多98(b),覆盖方式print
			//fmt.Println(buffer)

			//正常读取切出来的abc,byte强制类型转换成string
			fmt.Println(buffer[:n], string(buffer[:n]))
		}
	}

}

//带指针读取
func example2() {
	filename := "e:/test.txt" //内容为0123456789
	if f, err := os.Open(filename); err == nil {
		defer f.Close()
		buffer := make([]byte, 5)
		var n int
		//指定位置,从头向后偏移3字节开始读取长度5
		n, _ = f.ReadAt(buffer, 3)
		fmt.Println(n, f.Fd(), f.Name()) //5 384 e:/test.txt
		//[51 52 53 54 55] 5 5 34567
		fmt.Println("1:", buffer, len(buffer), cap(buffer), string(buffer[:n]))

		//Read不共用ReadAt的seek指针
		n, _ = f.Read(buffer)
		fmt.Println("2:", buffer, n, len(buffer), cap(buffer), string(buffer[:n]))
		n, _ = f.Read(buffer)
		fmt.Println("3:", buffer, n, len(buffer), cap(buffer), string(buffer[:n]))
		n, _ = f.Read(buffer)
		//读到结尾,如果有回车,就是13 10 两个字节\r\n
		fmt.Println("4:", buffer, n, len(buffer), cap(buffer), buffer[:n])

		//Seek(offset int64,whence int)的whence
		//whence=0 相对于开头,offset只能正,负报错
		//whence=1 相对于当前,offset可正可负,负指针不能超左边界
		//whence=2 相对于结尾,offset可正可负,负指针不能超左边界
		off, e := f.Seek(0, 1)
		if e == nil {
			fmt.Println(off, "------")
			buffer = make([]byte, 5)
			n, _ = f.Read(buffer)
			fmt.Println(n, buffer)
		} else {
			fmt.Println(e)
		}
	}
}

//带缓冲读取
func example3() {
	filename := "e:/test.txt" //内容为0123456789\nabc\nxyz
	if f, err := os.Open(filename); err == nil {
		defer f.Close()
		reader := bufio.NewReader(f) //File实现了Read方法
		//reader 可以按照字节或字符读取
		b1, err := reader.ReadBytes('5')
		fmt.Println("b1:", b1, string(b1), err) //012345 <nil>
		b2 := make([]byte, 3)
		n, err := reader.Read(b2)
		fmt.Println("b2:", n, b2, string(b2[:n]), err) //3 [54 55 56] 678 <nil>
		b3, err := reader.ReadBytes('\n')
		fmt.Println("b3:", b3, string(b3), err) //b3: [57 13 10] 9\n nil
		b4, err := reader.ReadSlice('\n')
		fmt.Println("b4:", b4, string(b4), err) // [97 98 99 13 10] abc \n nil
		line, err := reader.ReadString('\n')
		fmt.Println(line, err) //xyz EOF 意思是读到了文件末尾EOF还没有找到\n
		fmt.Println(
			strings.TrimRight(line, "\n"), //移除右边的换行符
		)

	}
}

//flag
func example4() {
	filename := "e:/test1.txt"
	flag := os.O_RDONLY //只读 写不报错但也写不进去
	//flag = os.O_WRONLY               //只写 从头写 文件必须存在
	//flag = os.O_WRONLY | os.O_CREATE //文件不存在就创建后写入,文件存在就写入从头写覆盖
	//flag = os.O_CREATE               //相当于 os.O_WRONLY | os.O_CREATE
	//flag = os.O_WRONLY | os.O_APPEND //文件末尾追加写,但是文件得存在
	//flag = os.O_APPEND               //相当于os.O_WRONLY|os.O_APPEND
	//flag = os.O_EXCL                 //不要单独使用
	//flag = os.O_EXCL | os.O_CREATE //文件存在报错。不存在创建从头写
	//flag = os.O_RDWR                 //既能读又能写。从头开始,要求文件存在

	f, err := os.OpenFile(filename, flag, 0o640)
	if err == nil {
		defer f.Close()
		fmt.Println(f)
		f.WriteString("abcd")
		f.WriteString("efg")
	} else {
		fmt.Println(err, "!!!")
	}
}

//带缓冲区的读写
func example5() {
	filename := "e:/test2.txt"
	flag := os.O_RDWR | os.O_CREATE | os.O_TRUNC
	if f, err := os.OpenFile(filename, flag, os.ModePerm); err == nil {
		defer f.Close()
		r := bufio.NewReader(f)
		w := bufio.NewWriter(f)
		w.WriteString("0123456789\n")
		w.WriteString("abcd\n")
		w.Flush() //写入

		f.Seek(0, 0) //底层共用同一个f,指针已经指到了EOF,00拉回到开始
		fmt.Println(r.ReadString('\n'))
		//f.Seek(0, 0) //这个seek在这里其实是没用的,内部有自己的记录,如果加了这个seek,读到结尾在读就又从头开始读了,文件读写中不要乱动指针
		fmt.Println(r.ReadString('\n'))
		//fmt.Println(r.ReadString('\n'))    //又循环去读了 配合 上面注释的f.seek
	} else {
		fmt.Println(err, "!!")
	}
}

func main() {
	//example1()
	//example2()
	//example3()
	//example4()
	example5()

}