1、os 包
1.1、创建文件
1 2 3 4 5 6 7
| f, err := os.Create("test.txt") if err != nil { fmt.Println(err) return } fmt.Println(f) f.Close()
|
使用 Create()
创建文件时:
- 如果文件不存在,则创建文件。
- 如果文件存在,则清空文件内内容。
- Create创建的文件任何人都可以读写。
1.2、打开文件,写入内容
打开文件有两种方式:
- Open():以只读的方式打开文件,若文件不存在则会打开失败
- OpenFile():打开文件时,可以传入打开方式,该函数的三个参数:
- 参数1:要打开的文件路径
- 参数2:文件打开模式,如
O_RDONLY
,O_WRONGLY
,O_RDWR
,还可以通过管道符来指定文件不存在时创建文件
- 参数3:文件创建时候的权限级别,在0-7之间,常用参数为6
1 2 3 4 5 6
| f, err := os.OpenFile("test.txt", os.O_APPEND | os.O_RDWR, os.ModeAppend) if err != nil { fmt.Println("open file err: ", err) return } f.Close()
|
常用的文件打开模式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| O_RDONLY int = syscall.O_RDONLY O_WRONGLY int = syscall.O_WRONGLY O_RDWR int = syscall.O_RDWR O_APPEND int = syscall.O_APPEND O_CREATE int = syscall.O_CREATE O_EXCL int = syscall.O_EXCL O_TRUNC int = syscall.O_TRUNC ```
## 1.3、写文件
### 写入字节 `Write()`
```go n, err := f.Write([]byte("hello")) if err != nil { fmt.Println("write err: ", err) return } fmt.Println("write number = ", n)
|
按字符串写 WriteString()
1 2 3 4 5 6 7
| n, err := f.WriteString(["hello") if err != nil { fmt.Println("write err: ", err) return } fmt.Println("write number = ", n)
|
修改文件的读写指针位置 Seek()
,包含两个参数:
- 参数1:偏移量,为正数时向文件尾偏移,为负数时向文件头偏移
- 参数2:偏移的开始位置,包括:
- io.SeekStart:从文件起始位置开始
- io.SeekCurrent:从文件当前位置开始
- io.SeekEnd:从文件末尾位置开始
Seek()
函数返回
1 2 3 4 5 6
| f, _ := os.OpenFile("test.txt",os.O_RDWR, 6) off, _ := f.Seek(5, io.SeekStart) fmt.Println(off) n, _ := f.WriteAt([]byte("111"), off) fmt.Println(n) f.Close()
|
1.4、文件读取
read() 实现的是按字节数读取:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| readByte := make([]byte, 128) for { n, err := f.Read(readByte) if err != nil && err != io.EOF{ fmt.Println("read file : ", err) break }
fmt.Println("read: ", string(readByte[:n])) if n < 128 { fmt.Println("read end") break } }
|
1.5、文件读取偏移量
文件读取时,是可以控制光标位置的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| f, err := os.OpenFile("test.txt", os.O_RDWR, os.ModePerm) if err != nil { fmt.Println("open err:", err) return } defer f.Close()
bs := []byte{0} _, err = f.Read(bs) if err != nil { fmt.Println("read err:", err) return } fmt.Println("读到的数据是:", string(bs))
_, err = f.Seek(4, io.SeekStart) if err != nil { fmt.Println("seek err:", err) return } _, err = f.Read(bs) if err != nil { fmt.Println("read err:", err) return } fmt.Println("读到的数据是:", string(bs))
|
通过记录光标的位置,可以实现断点续传:假设已经下载了1KB文件,即本地临时文件存储了1KB,此时断电,重启后通过本地文件大小、Seek()方法获取到上次读取文件的光标位置即可实现继续下载!
2、io/ioutil 包
2.1、io/ioutil 包文件读取
ioutil直接读取文件:
1 2 3 4 5 6
| ret, err := ioutil.ReadFile("test.txt") if err != nil { fmt.Println("read err :", err) return } fmt.Println(string(ret))
|
2.2、io/ioutil 包文件写入
1 2
| s := "你好世界" err := ioutil.WriteFile("test.txt", []byte(s), os.ModePerm)
|
3、bufio 包
3.1、bufio 的读操作
bufio封装了io.Reader、io.Writer接口对象,并创建了另一个也实现了该接口的对象:bufio.Reader、bufio.Writer。通过该实现,bufio实现了文件的缓冲区设计,可以大大提高文件I/O的效率。
使用bufio读取文件时,先将数据读入内存的缓冲区(缓冲区一般比要比程序中设置的文件接收对象要大),这样就可以有效降低直接I/O的次数。
bufio.Read([]byte)
相当于读取大小len(p)
的内容:
- 当缓冲区有内容时,将缓冲区内容全部填入p并清空缓冲区
- 当缓冲区没有内容且
len(p)>len(buf)
,即要读取的内容比缓冲区还要大,直接去文件读取即可
- 当缓冲区没有内容且
len(p)<len(buf)
,即要读取的内容比缓冲区小,读取文件内容并填满缓冲区,并将p填满
- 以后再次读取时,缓冲区有内容,将缓冲区内容全部填入p并清空缓冲区(和第一步一致)
示例:
1 2 3 4 5 6
| reader := bufio.NewReader(f)
byt, _ := reader.ReadBytes('\n') fmt.Println(string(byt))
|
ReadString() 函数也具有同样的功能,且能直接读取到字符串数据,无需转换,示例:读取大文件的全部数据
1 2 3 4 5 6 7 8 9 10 11 12 13
| reader := bufio.NewReader(f) for { str, err := reader.ReadString('\n') if err != nil && err != io.EOF { fmt.Println("read err: ", err) break } fmt.Println("str = ", str) if err == io.EOF { fmt.Print("read end") break } }
|
在Unix设计思想中,一切皆文件,命令行输入也可以作为文件读入:
1 2
| reader := bufio.NewReader(os.Stdin) s, _ := reader.ReadString("-")
|
缓冲的思想:通过bufio,数据被写入用户缓冲,再进入系统缓冲,最后由操作系统将系统缓冲区的数据写入磁盘。
3.2、bufio 的写操作
1 2 3 4 5 6 7
| writer := bufio.NewWriter(f) _, err = writer.WriteString("hello world!") if err != nil { fmt.Println("write err:", err) return } writer.Flush()
|