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()
}